diff --git a/.ci/flutter_master.version b/.ci/flutter_master.version index d9d23f301e6c..1623836863db 100644 --- a/.ci/flutter_master.version +++ b/.ci/flutter_master.version @@ -1 +1 @@ -d117642c18e0d5e3a96ae00d4340b1b0724de24c +fb03253e32ce6aba92872ed9c1224e999ec6abcb diff --git a/.ci/flutter_stable.version b/.ci/flutter_stable.version index ad241bc2bef7..cab742975b85 100644 --- a/.ci/flutter_stable.version +++ b/.ci/flutter_stable.version @@ -1 +1 @@ -2c9eb20739dfec95e2c74bd3dfa4601b0a8a36aa +db50e20168db8fee486b9abf32fc912de3bc5b6a diff --git a/.github/remove_cicd.yml b/.github/remove_cicd.yml new file mode 100644 index 000000000000..6f5ff9d0596f --- /dev/null +++ b/.github/remove_cicd.yml @@ -0,0 +1,65 @@ +# Copyright 2024 The Flutter Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +name: Remove outdated CICD Label + +on: + pull_request_target: + types: [synchronize] + +permissions: + pull-requests: write + issues: write + +jobs: + remove_cicd_label: + if: contains(github.event.pull_request.labels.*.name, 'CICD') + runs-on: ubuntu-latest + steps: + - name: Check if label was added before push + id: check_timing + run: | + # Get push time (commit date of the head SHA) + PUSH_TIME='${{ github.event.pull_request.updated_at }}' + echo "Push time: $PUSH_TIME" + + # Get latest CICD labeling event time from the last 100 events + LABEL_TIME=$(gh api graphql -f query=' + query($owner: String!, $repo: String!, $pr: Int!) { + repository(owner: $owner, name: $repo) { + pullRequest(number: $pr) { + timelineItems(last: 100, itemTypes: [LABELED_EVENT]) { + nodes { + ... on LabeledEvent { + label { name } + createdAt + } + } + } + } + } + }' -f owner=${{ github.repository_owner }} -f repo=${{ github.event.repository.name }} -F pr=${{ github.event.pull_request.number }} \ + --jq '.data.repository.pullRequest.timelineItems.nodes | map(select(.label.name == "CICD")) | last | .createdAt') + echo "Label time: $LABEL_TIME" + + if [[ -z "$LABEL_TIME" ]]; then + # Label exists on PR (checked by job 'if') but not in last 100 events -> must be very old + echo "should_remove=true" >> "$GITHUB_OUTPUT" + echo "Result: Label found on PR but not in recent timeline events. Assuming it is old." + elif [[ "$LABEL_TIME" < "$PUSH_TIME" ]]; then + echo "should_remove=true" >> "$GITHUB_OUTPUT" + echo "Result: Label added at $LABEL_TIME is older than push at $PUSH_TIME. Removing." + else + echo "should_remove=false" >> "$GITHUB_OUTPUT" + echo "Result: Label added at $LABEL_TIME is newer than or same as push at $PUSH_TIME. Skipping removal." + fi + env: + GITHUB_TOKEN: ${{ github.token }} + + - name: Remove outdated CICD label + if: steps.check_timing.outputs.should_remove == 'true' + run: | + gh pr edit ${{ github.event.pull_request.number }} -R ${{ github.repository }} --remove-label "CICD" + env: + GITHUB_TOKEN: ${{ github.token }} diff --git a/.github/workflows/batch_release_pr.yml b/.github/workflows/batch_release_pr.yml index 12e0278fb96c..2baaf81fa0ba 100644 --- a/.github/workflows/batch_release_pr.yml +++ b/.github/workflows/batch_release_pr.yml @@ -5,10 +5,14 @@ on: types: [batch-release-pr] jobs: - create_release_pr: + create_batch_release_branch: runs-on: ubuntu-latest + permissions: + contents: write # Grants write permission to create a branch. env: BRANCH_NAME: ${{ github.event.client_payload.package }}-${{ github.run_id }}-${{ github.run_attempt }} + outputs: + branch_created: ${{ steps.check-branch-exists.outputs.exists }} steps: - name: checkout repository uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd @@ -36,15 +40,29 @@ jobs: echo "exists=false" >> $GITHUB_OUTPUT fi - - name: Create batch release PR - if: steps.check-branch-exists.outputs.exists == 'true' - uses: peter-evans/create-pull-request@c0f553fe549906ede9cf27b5156039d195d2ece0 + create_release_pr: + needs: create_batch_release_branch + if: needs.create_batch_release_branch.outputs.branch_created == 'true' + runs-on: ubuntu-latest + permissions: + # The create-pull-request action needs both content and pull-requests permissions. + pull-requests: write + contents: write + env: + BRANCH_NAME: ${{ github.event.client_payload.package }}-${{ github.run_id }}-${{ github.run_attempt }} + steps: + - name: checkout repository + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd with: - token: ${{ secrets.GITHUB_TOKEN }} - commit-message: "[${{ github.event.client_payload.package }}] Batch release" - title: "[${{ github.event.client_payload.package }}] Batch release" - body: "This PR was created automatically to batch release the `${{ github.event.client_payload.package }}`." - branch: ${{ env.BRANCH_NAME }} - base: release-${{ github.event.client_payload.package }} + ref: ${{ env.BRANCH_NAME }} + - name: Create batch release PR + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + gh pr create \ + --base "release-${{ github.event.client_payload.package }}" \ + --head "${{ env.BRANCH_NAME }}" \ + --title "[${{ github.event.client_payload.package }}] Batch release" \ + --body "This PR was created automatically to batch release the \`${{ github.event.client_payload.package }}\`." diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index c86bbd62a607..ab14d6890c24 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -40,7 +40,7 @@ jobs: # because there doesn't appear to be anything to wait for. To avoid that, # explicitly wait for one LUCI test by name first. - name: Wait for test check-in - uses: lewagon/wait-on-check-action@74049309dfeff245fe8009a0137eacf28136cb3c + uses: lewagon/wait-on-check-action@a08fbe2b86f9336198f33be6ad9c16b96f92799c with: ref: ${{ github.sha }} check-name: 'Linux ci_yaml packages roller' @@ -52,7 +52,7 @@ jobs: # This workflow should be the last to run. So wait for all the other tests to succeed. - name: Wait on all tests - uses: lewagon/wait-on-check-action@74049309dfeff245fe8009a0137eacf28136cb3c + uses: lewagon/wait-on-check-action@a08fbe2b86f9336198f33be6ad9c16b96f92799c with: ref: ${{ github.sha }} running-workflow-name: 'release' diff --git a/.github/workflows/release_from_branches.yml b/.github/workflows/release_from_branches.yml index a235a2576ef3..5286cc18e041 100644 --- a/.github/workflows/release_from_branches.yml +++ b/.github/workflows/release_from_branches.yml @@ -5,7 +5,7 @@ on: - 'release-go_router' jobs: release: - uses: ./.github/workflows/resuable_release.yml + uses: ./.github/workflows/reusable_release.yml with: is-batch-release: true branch-name: '${{ github.ref_name }}' diff --git a/.github/workflows/reusable_release.yml b/.github/workflows/reusable_release.yml index 6d519bec1e0b..e6fc6f2d1c4c 100644 --- a/.github/workflows/reusable_release.yml +++ b/.github/workflows/reusable_release.yml @@ -44,7 +44,7 @@ jobs: # because there doesn't appear to be anything to wait for. To avoid that, # explicitly wait for one LUCI test by name first. - name: Wait for test check-in - uses: lewagon/wait-on-check-action@74049309dfeff245fe8009a0137eacf28136cb3c + uses: lewagon/wait-on-check-action@a08fbe2b86f9336198f33be6ad9c16b96f92799c with: ref: ${{ github.sha }} check-name: 'Linux ci_yaml packages roller' @@ -56,7 +56,7 @@ jobs: # This workflow should be the last to run. So wait for all the other tests to succeed. - name: Wait on all tests - uses: lewagon/wait-on-check-action@74049309dfeff245fe8009a0137eacf28136cb3c + uses: lewagon/wait-on-check-action@a08fbe2b86f9336198f33be6ad9c16b96f92799c with: ref: ${{ github.sha }} running-workflow-name: 'release' diff --git a/.github/workflows/sync_release_pr.yml b/.github/workflows/sync_release_pr.yml index a53436ce0ffd..66233b6839d9 100644 --- a/.github/workflows/sync_release_pr.yml +++ b/.github/workflows/sync_release_pr.yml @@ -9,17 +9,21 @@ on: jobs: create_sync_pr: runs-on: ubuntu-latest + permissions: + # The create-pull-request action needs both content and pull-requests permissions. + contents: write + pull-requests: write steps: - name: Checkout repository uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd - name: Create Pull Request - uses: peter-evans/create-pull-request@c0f553fe549906ede9cf27b5156039d195d2ece0 - with: - token: ${{ secrets.GITHUB_TOKEN }} - commit-message: "Sync ${{ github.ref_name }} to main" - title: "Sync ${{ github.ref_name }} to main" - body: "This automated PR syncs the changes from the release branch ${{ github.ref_name }} back to the main branch." - branch: ${{ github.ref_name }} - base: main - labels: "post-${{ github.ref_name }}" + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + gh pr create \ + --base "main" \ + --head "${{ github.ref_name }}" \ + --title "Sync ${{ github.ref_name }} to main" \ + --body "This automated PR syncs the changes from the release branch ${{ github.ref_name }} back to the main branch." \ + --label "post-${{ github.ref_name }}" diff --git a/CODEOWNERS b/CODEOWNERS deleted file mode 100644 index a49a588717fc..000000000000 --- a/CODEOWNERS +++ /dev/null @@ -1,127 +0,0 @@ -# Below is a list of Flutter team members who are suggested reviewers -# for contributions to packages in this repository. -# -# These names are just suggestions. It is fine to have your changes -# reviewed by someone else. - -packages/animations/** @hannah-hyj -packages/camera/** @bparrishMines -packages/cross_file/** @stuartmorgan-g -packages/cupertino_ui/** @dkwingsmt -packages/extension_google_sign_in_as_googleapis_auth/** @stuartmorgan-g -packages/file_selector/** @stuartmorgan-g -packages/flutter_lints/** @chunhtai -packages/flutter_template_images/** @stuartmorgan-g -packages/go_router/** @chunhtai -packages/go_router_builder/** @chunhtai -packages/google_adsense/** @sokoloff06 @ditman -packages/google_identity_services_web/** @mdebbar -packages/google_fonts/** @Piinks -packages/google_maps_flutter/** @stuartmorgan-g -packages/google_sign_in/** @stuartmorgan-g -packages/image_picker/** @tarrinneal -packages/interactive_media_ads/** @bparrishMines -packages/in_app_purchase/** @bparrishMines -packages/local_auth/** @stuartmorgan-g -packages/material_ui/** @qunccccccc -packages/metrics_center/** @bkonyi -packages/multicast_dns/** @vashworth -packages/path_provider/** @stuartmorgan-g -packages/pigeon/** @tarrinneal -packages/platform/** @stuartmorgan-g -packages/plugin_platform_interface/** @stuartmorgan-g -packages/pointer_interceptor/** @ditman -packages/quick_actions/** @bparrishMines -packages/rfw/** @Hixie -packages/shared_preferences/** @tarrinneal -packages/standard_message_codec/** @stuartmorgan-g -packages/two_dimensional_scrollables/** @Piinks -packages/url_launcher/** @stuartmorgan-g -packages/vector_graphics/** @jtmcdole -packages/vector_graphics_codec/** @jtmcdole -packages/vector_graphics_compiler/** @jtmcdole -packages/video_player/** @tarrinneal -packages/web_benchmarks/** @yjbanov -packages/webview_flutter/** @bparrishMines -packages/xdg_directories/** @stuartmorgan-g -third_party/packages/cupertino_icons/** @victorsanni -third_party/packages/cupertino_icons/test/goldens/** @LongCatIsLooong -third_party/packages/flutter_svg/** @domesticmouse -third_party/packages/flutter_svg_test/** @domesticmouse -third_party/packages/mustache_template/** @bkonyi @parlough -third_party/packages/path_parsing/** @domesticmouse - -# Plugin platform implementation rules. These should stay last, since the last -# matching entry takes precedence. - -# - Web -packages/camera/camera_web/** @mdebbar -packages/file_selector/file_selector_web/** @mdebbar -packages/google_maps_flutter/google_maps_flutter_web/** @mdebbar -packages/google_sign_in/google_sign_in_web/** @mdebbar -packages/image_picker/image_picker_for_web/** @mdebbar -packages/pointer_interceptor/pointer_interceptor_web/** @mdebbar -packages/shared_preferences/shared_preferences_web/** @mdebbar -packages/url_launcher/url_launcher_web/** @mdebbar -packages/video_player/video_player_web/** @mdebbar -packages/webview_flutter/webview_flutter_web/** @mdebbar - -# - Android -packages/camera/camera_android/** @camsim99 -packages/camera/camera_android_camerax/** @camsim99 -packages/espresso/** @jesswrd -packages/file_selector/file_selector_android/** @mboetger -packages/flutter_plugin_android_lifecycle/** @reidbaker -packages/google_maps_flutter/google_maps_flutter_android/** @reidbaker -packages/google_sign_in/google_sign_in_android/** @reidbaker -packages/image_picker/image_picker_android/** @gmackall -packages/in_app_purchase/in_app_purchase_android/** @gmackall -packages/local_auth/local_auth_android/** @mboetger -packages/path_provider/path_provider_android/** @camsim99 -packages/quick_actions/quick_actions_android/** @jesswrd -packages/shared_preferences/shared_preferences_android/** @jesswrd -packages/url_launcher/url_launcher_android/** @gmackall -packages/video_player/video_player_android/** @mboetger -# Owned by ecosystem team for now during the wrapper evaluation. -packages/webview_flutter/webview_flutter_android/** @bparrishMines - -# - Darwin -packages/camera/camera_avfoundation/** @hellohuanlin @louisehsu -packages/file_selector/file_selector_ios/** @okorohelijah @vashworth -packages/file_selector/file_selector_macos/** @okorohelijah @vashworth -packages/google_maps_flutter/google_maps_flutter_ios/** @vashworth @LongCatIsLooong -packages/google_maps_flutter/google_maps_flutter_ios_sdk9/** @vashworth @LongCatIsLooong -packages/google_maps_flutter/google_maps_flutter_ios_sdk10/** @vashworth @LongCatIsLooong -packages/google_sign_in/google_sign_in_ios/** @LongCatIsLooong @okorohelijah -packages/image_picker/image_picker_ios/** @okorohelijah @vashworth -packages/image_picker/image_picker_macos/** @okorohelijah @vashworth -packages/in_app_purchase/in_app_purchase_storekit/** @louisehsu @LongCatIsLooong -packages/local_auth/local_auth_darwin/** @louisehsu @okorohelijah -packages/path_provider/path_provider_foundation/** @LongCatIsLooong @vashworth -packages/pointer_interceptor/pointer_interceptor_ios/** @louisehsu @hellohuanlin -packages/quick_actions/quick_actions_ios/** @louisehsu @LongCatIsLooong -packages/shared_preferences/shared_preferences_foundation/** @tarrinneal -packages/url_launcher/url_launcher_ios/** @vashworth @LongCatIsLooong -packages/url_launcher/url_launcher_macos/** @vashworth @LongCatIsLooong -packages/video_player/video_player_avfoundation/** @hellohuanlin @louisehsu -packages/webview_flutter/webview_flutter_wkwebview/** @LongCatIsLooong @hellohuanlin - -# - Linux -packages/file_selector/file_selector_linux/** @robert-ancell @stuartmorgan-g -packages/image_picker/image_picker_linux/** @robert-ancell @stuartmorgan-g -packages/path_provider/path_provider_linux/** @robert-ancell @stuartmorgan-g -packages/shared_preferences/shared_preferences_linux/** @robert-ancell @stuartmorgan-g -packages/url_launcher/url_launcher_linux/** @robert-ancell @stuartmorgan-g - -# - Windows -packages/camera/camera_windows/** @stuartmorgan-g -packages/file_selector/file_selector_windows/** @stuartmorgan-g -packages/image_picker/image_picker_windows/** @stuartmorgan-g -packages/local_auth/local_auth_windows/** @stuartmorgan-g -packages/path_provider/path_provider_windows/** @stuartmorgan-g -packages/shared_preferences/shared_preferences_windows/** @stuartmorgan-g -packages/url_launcher/url_launcher_windows/** @stuartmorgan-g - -# - DevTools extensions -# @adsonpleal is the actual maintainer of shared_preferences_tool but is not yet a committer, so can't be listed as the owner. -packages/shared_preferences/shared_preferences_tool/** @tarrinneal diff --git a/SUGGESTED_REVIEWERS.md b/SUGGESTED_REVIEWERS.md new file mode 100644 index 000000000000..ad9a954e7683 --- /dev/null +++ b/SUGGESTED_REVIEWERS.md @@ -0,0 +1,187 @@ +Below is a list of Flutter team members who are suggested reviewers +for contributions to packages in this repository. + +These names are just suggestions. It is fine to have your changes +reviewed by someone else. + +`animations`: + - @hannah-hyj + +`camera`: + - **Cross-platform**: @bparrishMines + - **Android**: @camsim99 + - **iOS**: @hellohuanlin, @louisehsu + - **Web**: @mdebbar + - **Windows**: @stuartmorgan-g + +`cross_file`: + - @stuartmorgan-g + +`cupertino_icons`: + - @victorsanni + +`cupertino_ui`: + - @dkwingsmt + +`espresso`: + - @jesswrd + +`extension_google_sign_in_as_googleapis_auth`: + - @stuartmorgan-g + +`file_selector`: + - **Cross-platform**: @stuartmorgan-g + - **Android**: @mboetger + - **iOS**: @okorohelijah, @vashworth + - **Linux**: @robert-ancell, @stuartmorgan-g + - **macOS**: @okorohelijah, @vashworth + - **Web**: @mdebbar + - **Windows**: @stuartmorgan-g + +`flutter_lints`: + - @chunhtai + +`flutter_plugin_android_lifecycle`: + - @reidbaker + +`flutter_svg, flutter_svg_test`: + - @domesticmouse + +`flutter_template_images`: + - @stuartmorgan-g + +`go_router / go_router_builder`: + - @chunhtai + +`google_adsense`: + - @sokoloff06, @ditman + +`google_identity_services_web`: + - @mdebbar + +`google_fonts`: + - @Piinks + +`google_maps_flutter`: + - **Cross-platform**: @stuartmorgan-g + - **Android**: @reidbaker + - **iOS**: @vashworth, @LongCatIsLooong + - **Web**: @mdebbar + +`google_sign_in`: + - **Cross-platform**: @stuartmorgan-g + - **Android**: @reidbaker + - **iOS**: @LongCatIsLooong, @okorohelijah + - **Web**: @mdebbar + +`image_picker`: + - **Cross-platform**: @tarrinneal + - **Android**: @gmackall + - **iOS**: @okorohelijah, @vashworth + - **Linux**: @robert-ancell, @stuartmorgan-g + - **macOS**: @okorohelijah, @vashworth + - **Web**: @mdebbar + - **Windows**: @stuartmorgan-g + +`interactive_media_ads`: + - @bparrishMines + +`in_app_purchase`: + - **Cross-platform**: @bparrishMines + - **Android**: @gmackall + - **iOS**: @louisehsu, @LongCatIsLooong + +`local_auth`: + - **Cross-platform**: @stuartmorgan-g + - **Android**: @mboetger + - **iOS/macOS**: @louisehsu, @okorohelijah + - **Windows**: @stuartmorgan-g + +`material_ui`: + - @qunccccccc + +`metrics_center`: + - @bkonyi + +`multicast_dns`: + - @vashworth + +`mustache_template`: + - @bkonyi, @parlough + +`path_parsing`: + - @domesticmouse + +`path_provider`: + - **Cross-platform**: @stuartmorgan-g + - **Android**: @camsim99 + - **iOS/macOS**: @LongCatIsLooong, @vashworth + - **Linux**: @robert-ancell, @stuartmorgan-g + - **Windows**: @stuartmorgan-g + +`pigeon`: + - @tarrinneal + +`platform`: + - @stuartmorgan-g + +`plugin_platform_interface`: + - @stuartmorgan-g + +`pointer_interceptor`: + - **Cross-platform**: @ditman + - **iOS**: @louisehsu, @hellohuanlin + - **Web**: @mdebbar + +`quick_actions`: + - **Cross-platform**: @bparrishMines + - **Android**: @jesswrd + - **iOS**: @louisehsu, @LongCatIsLooong + +`rfw`: + - @Hixie + +`shared_preferences`: + - **Cross-platform**: @tarrinneal + - **Android**: @jesswrd + - **iOS/macOS**: @tarrinneal + - **Linux**: @robert-ancell, @stuartmorgan-g + - **Windows**: @stuartmorgan-g + - **Web**: @mdebbar + - **Devtools**: @adsonpleal + +`standard_message_codec`: + - @stuartmorgan-g + +`two_dimensional_scrollables`: + - @Piinks + +`url_launcher`: + - **Cross-platform**: @stuartmorgan-g + - **Android**: @gmackall + - **iOS**: @vashworth, @LongCatIsLooong + - **Linux**: @robert-ancell, @stuartmorgan-g + - **macOS**: @vashworth, @LongCatIsLooong + - **Windows**: @stuartmorgan-g + - **Web**: @mdebbar + +`vector_graphics, vector_graphics_codec, vector_graphics_compiler`: + - @jtmcdole + +`video_player`: + - **Cross-platform**: @tarrinneal + - **Android**: @mboetger + - **iOS/macOS**: @hellohuanlin, @louisehsu + - **Web**: @mdebbar + +`web_benchmarks`: + - @yjbanov + +`webview_flutter`: + - **Cross-platform**: @bparrishMines + - **Android**: @bparrishMines + - **iOS/macOS**: @bparrishMines, @LongCatIsLooong, @hellohuanlin + - **Web**: @mdebbar + +`xdg_directories`: + - @stuartmorgan-g diff --git a/analysis_options.yaml b/analysis_options.yaml index 7a97623b839f..5a160d9d8582 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -196,6 +196,7 @@ linter: - type_annotate_public_apis - type_init_formals - type_literal_in_constant_pattern + - unintended_html_in_doc_comment # DIFFERENT FROM FLUTTER/FLUTTER: Disabled due to an issue that has been fixed, so just hasn't been adopted there yet. - unawaited_futures # DIFFERENT FROM FLUTTER/FLUTTER: It's disabled there for "too many false positives"; that's not an issue here, and missing awaits have caused production issues in plugins. - unnecessary_await_in_return - unnecessary_brace_in_string_interps diff --git a/packages/animations/CHANGELOG.md b/packages/animations/CHANGELOG.md index 6d7110f9b8ec..0779bea39e8a 100644 --- a/packages/animations/CHANGELOG.md +++ b/packages/animations/CHANGELOG.md @@ -1,6 +1,7 @@ -## NEXT +## 2.1.2 * Updates minimum supported SDK version to Flutter 3.35/Dart 3.9. +* Adds an example of using `OpenContainer` ## 2.1.1 diff --git a/packages/animations/lib/src/open_container.dart b/packages/animations/lib/src/open_container.dart index 10dd2b2f5e70..4683c3597642 100644 --- a/packages/animations/lib/src/open_container.dart +++ b/packages/animations/lib/src/open_container.dart @@ -66,7 +66,46 @@ typedef ClosedCallback = void Function(S data); /// `T` refers to the type of data returned by the route when the container /// is closed. This value can be accessed in the `onClosed` function. /// -// TODO(goderbauer): Add example animations and sample code. +/// The following example shows an [OpenContainer] that transforms a blue +/// container widget into a full screen page using the Material container +/// transform animation. When the user taps the closed widget, the container +/// expands and morphs into the destination page defined in [openBuilder], +/// while the original widget from [closedBuilder] fades out during the +/// transition. +/// +/// ```dart +/// OpenContainer( +/// transitionDuration: const Duration(milliseconds: 500), +/// transitionType: ContainerTransitionType.fadeThrough, +/// openBuilder: (context, action) { +/// return Scaffold( +/// appBar: AppBar(title: const Text('Details Page')), +/// body: const Center( +/// child: Text( +/// 'This page opened with Container Transform animation', +/// style: TextStyle(fontSize: 18), +/// textAlign: TextAlign.center, +/// ), +/// ), +/// ); +/// }, +/// closedBuilder: (context, action) { +/// return Container( +/// width: 200, +/// height: 120, +/// alignment: Alignment.center, +/// decoration: BoxDecoration( +/// color: Colors.blue, +/// borderRadius: BorderRadius.circular(16), +/// ), +/// child: const Text( +/// 'Open Details', +/// style: TextStyle(color: Colors.white, fontSize: 18), +/// ), +/// ); +/// }, +/// ), +/// ``` /// /// See also: /// diff --git a/packages/animations/pubspec.yaml b/packages/animations/pubspec.yaml index 012218b3db2b..0670649c6e95 100644 --- a/packages/animations/pubspec.yaml +++ b/packages/animations/pubspec.yaml @@ -2,7 +2,7 @@ name: animations description: Fancy pre-built animations that can easily be integrated into any Flutter application. repository: https://github.com/flutter/packages/tree/main/packages/animations issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+animations%22 -version: 2.1.1 +version: 2.1.2 environment: sdk: ^3.9.0 diff --git a/packages/camera/camera/CHANGELOG.md b/packages/camera/camera/CHANGELOG.md index 397973454698..557e16ea59e4 100644 --- a/packages/camera/camera/CHANGELOG.md +++ b/packages/camera/camera/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.12.0+1 + +* Makes `Optional.of` constructor `const`. + ## 0.12.0 * Adds support for video stabilization. @@ -838,4 +842,4 @@ Method changes: ## 0.0.1 -* Initial release \ No newline at end of file +* Initial release diff --git a/packages/camera/camera/lib/src/camera_controller.dart b/packages/camera/camera/lib/src/camera_controller.dart index 53e029b0faad..d941c2e85f66 100644 --- a/packages/camera/camera/lib/src/camera_controller.dart +++ b/packages/camera/camera/lib/src/camera_controller.dart @@ -1049,13 +1049,7 @@ class Optional extends IterableBase { const Optional.absent() : _value = null; /// Constructs an Optional of the given [value]. - /// - /// Throws [ArgumentError] if [value] is null. - Optional.of(T value) : _value = value { - // TODO(cbracken): Delete and make this ctor const once mixed-mode - // execution is no longer around. - ArgumentError.checkNotNull(value); - } + const Optional.of(T value) : _value = value; /// Constructs an Optional of the given [value]. /// diff --git a/packages/camera/camera/pubspec.yaml b/packages/camera/camera/pubspec.yaml index 1c9e8bb0b145..2d5967181c32 100644 --- a/packages/camera/camera/pubspec.yaml +++ b/packages/camera/camera/pubspec.yaml @@ -4,7 +4,7 @@ description: A Flutter plugin for controlling the camera. Supports previewing Dart. repository: https://github.com/flutter/packages/tree/main/packages/camera/camera issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+camera%22 -version: 0.12.0 +version: 0.12.0+1 environment: sdk: ^3.9.0 diff --git a/packages/camera/camera/test/camera_test.dart b/packages/camera/camera/test/camera_test.dart index 97f4f2b424a9..913d3391cd9e 100644 --- a/packages/camera/camera/test/camera_test.dart +++ b/packages/camera/camera/test/camera_test.dart @@ -3664,7 +3664,7 @@ void main() { cameraController.value = cameraController.value.copyWith( isPreviewPaused: false, deviceOrientation: DeviceOrientation.portraitUp, - lockedCaptureOrientation: Optional.of( + lockedCaptureOrientation: const Optional.of( DeviceOrientation.landscapeRight, ), ); diff --git a/packages/camera/camera_android/CHANGELOG.md b/packages/camera/camera_android/CHANGELOG.md index 9357004bb894..0bf9721e6ab9 100644 --- a/packages/camera/camera_android/CHANGELOG.md +++ b/packages/camera/camera_android/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.10.10+16 + +* Updates build files from Groovy to Kotlin. + ## 0.10.10+15 * Updates example to demonstrate correct exception handling for async return statements, ensuring exceptions thrown during return within try blocks are properly caught as per [dart-lang/sdk#44395](https://github.com/dart-lang/sdk/issues/44395). diff --git a/packages/camera/camera_android/android/build.gradle b/packages/camera/camera_android/android/build.gradle.kts similarity index 51% rename from packages/camera/camera_android/android/build.gradle rename to packages/camera/camera_android/android/build.gradle.kts index 6236cce21649..22a4dfb62033 100644 --- a/packages/camera/camera_android/android/build.gradle +++ b/packages/camera/camera_android/android/build.gradle.kts @@ -1,6 +1,5 @@ group = "io.flutter.plugins.camera" version = "1.0-SNAPSHOT" -def args = ["-Xlint:deprecation","-Xlint:unchecked"] buildscript { repositories { @@ -13,18 +12,21 @@ buildscript { } } -rootProject.allprojects { +allprojects { repositories { google() mavenCentral() } } -project.getTasks().withType(JavaCompile){ - options.compilerArgs.addAll(args) +tasks.withType().configureEach { + options.compilerArgs.add("-Xlint:deprecation") + options.compilerArgs.add("-Xlint:unchecked") } -apply plugin: 'com.android.library' +plugins { + id("com.android.library") +} android { buildFeatures { @@ -41,7 +43,7 @@ android { lint { checkAllWarnings = true warningsAsErrors = true - disable 'AndroidGradlePluginVersion', 'InvalidPackage', 'GradleDependency', 'NewerVersionAvailable' + disable.addAll(setOf("AndroidGradlePluginVersion", "InvalidPackage", "GradleDependency", "NewerVersionAvailable")) } compileOptions { @@ -50,18 +52,20 @@ android { } testOptions { - unitTests.includeAndroidResources = true - unitTests.returnDefaultValues = true - unitTests.all { - // The org.gradle.jvmargs property that may be set in gradle.properties does not impact - // the Java heap size when running the Android unit tests. The following property here - // sets the heap size to a size large enough to run the robolectric tests across - // multiple SDK levels. - jvmArgs "-Xmx4G" - testLogging { - events "passed", "skipped", "failed", "standardOut", "standardError" - outputs.upToDateWhen {false} - showStandardStreams = true + unitTests { + isIncludeAndroidResources = true + isReturnDefaultValues = true + all { + it.outputs.upToDateWhen { false } + it.testLogging { + events("passed", "skipped", "failed", "standardOut", "standardError") + showStandardStreams = true + } + // The org.gradle.jvmargs property that may be set in gradle.properties does not impact + // the Java heap size when running the Android unit tests. The following property here + // sets the heap size to a size large enough to run the robolectric tests across + // multiple SDK levels. + it.jvmArgs("-Xmx4G") } } } diff --git a/packages/camera/camera_android/android/settings.gradle b/packages/camera/camera_android/android/settings.gradle deleted file mode 100644 index 94a1bae9d6cd..000000000000 --- a/packages/camera/camera_android/android/settings.gradle +++ /dev/null @@ -1 +0,0 @@ -rootProject.name = 'camera_android' diff --git a/packages/camera/camera_android/android/settings.gradle.kts b/packages/camera/camera_android/android/settings.gradle.kts new file mode 100644 index 000000000000..0006625daf4e --- /dev/null +++ b/packages/camera/camera_android/android/settings.gradle.kts @@ -0,0 +1 @@ +rootProject.name = "camera_android" diff --git a/packages/camera/camera_android/example/lib/camera_controller.dart b/packages/camera/camera_android/example/lib/camera_controller.dart index 8215ef8fed54..33cafe13e447 100644 --- a/packages/camera/camera_android/example/lib/camera_controller.dart +++ b/packages/camera/camera_android/example/lib/camera_controller.dart @@ -478,13 +478,7 @@ class Optional extends IterableBase { const Optional.absent() : _value = null; /// Constructs an Optional of the given [value]. - /// - /// Throws [ArgumentError] if [value] is null. - Optional.of(T value) : _value = value { - // TODO(cbracken): Delete and make this ctor const once mixed-mode - // execution is no longer around. - ArgumentError.checkNotNull(value); - } + const Optional.of(T value) : _value = value; /// Constructs an Optional of the given [value]. /// diff --git a/packages/camera/camera_android/pubspec.yaml b/packages/camera/camera_android/pubspec.yaml index 4448279e3a32..34ffc900e502 100644 --- a/packages/camera/camera_android/pubspec.yaml +++ b/packages/camera/camera_android/pubspec.yaml @@ -3,7 +3,7 @@ description: Android implementation of the camera plugin. repository: https://github.com/flutter/packages/tree/main/packages/camera/camera_android issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+camera%22 -version: 0.10.10+15 +version: 0.10.10+16 environment: sdk: ^3.9.0 diff --git a/packages/camera/camera_android_camerax/CHANGELOG.md b/packages/camera/camera_android_camerax/CHANGELOG.md index 4e9229a78da6..c6a099c854d7 100644 --- a/packages/camera/camera_android_camerax/CHANGELOG.md +++ b/packages/camera/camera_android_camerax/CHANGELOG.md @@ -1,3 +1,11 @@ +## 0.7.1+2 + +* Fixes dartdoc comments that accidentally used HTML. + +## 0.7.1+1 + +* Updates build files from Groovy to Kotlin. + ## 0.7.1 * Removes outdated restrictions against concurrent camera use cases. @@ -518,4 +526,4 @@ this plugin should now be compatible with [google_ml_kit_flutter](https://github * Displaying a live camera preview * Image streaming - See [`README.md`](README.md) for more details on the limitations of this implementation. \ No newline at end of file + See [`README.md`](README.md) for more details on the limitations of this implementation. diff --git a/packages/camera/camera_android_camerax/android/build.gradle b/packages/camera/camera_android_camerax/android/build.gradle.kts similarity index 50% rename from packages/camera/camera_android_camerax/android/build.gradle rename to packages/camera/camera_android_camerax/android/build.gradle.kts index 065738fc7ba2..13da169a49e9 100644 --- a/packages/camera/camera_android_camerax/android/build.gradle +++ b/packages/camera/camera_android_camerax/android/build.gradle.kts @@ -1,8 +1,10 @@ +import org.jetbrains.kotlin.gradle.dsl.JvmTarget + group = "io.flutter.plugins.camerax" version = "1.0" buildscript { - ext.kotlin_version = '2.3.0' + val kotlinVersion = "2.3.0" repositories { google() mavenCentral() @@ -10,19 +12,27 @@ buildscript { dependencies { classpath("com.android.tools.build:gradle:8.13.1") - classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version") + classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion") } } -rootProject.allprojects { +allprojects { repositories { google() mavenCentral() } } -apply plugin: 'com.android.library' -apply plugin: 'kotlin-android' +plugins { + id("com.android.library") + id("kotlin-android") +} + +kotlin { + compilerOptions { + jvmTarget = JvmTarget.fromTarget(JavaVersion.VERSION_17.toString()) + } +} android { namespace = "io.flutter.plugins.camerax" @@ -34,11 +44,6 @@ android { targetCompatibility = JavaVersion.VERSION_17 } - kotlinOptions { - // This must match the Java version provided in compileOptions. - jvmTarget = JavaVersion.VERSION_17.toString() - } - defaultConfig { // CameraX APIs require API 23 or later. minSdk = 23 @@ -46,18 +51,20 @@ android { } testOptions { - unitTests.includeAndroidResources = true - unitTests.returnDefaultValues = true - unitTests.all { - // The org.gradle.jvmargs property that may be set in gradle.properties does not impact - // the Java heap size when running the Android unit tests. The following property here - // sets the heap size to a size large enough to run the robolectric tests across - // multiple SDK levels. - jvmArgs "-Xmx1G" - testLogging { - events "passed", "skipped", "failed", "standardOut", "standardError" - outputs.upToDateWhen {false} - showStandardStreams = true + unitTests { + isIncludeAndroidResources = true + isReturnDefaultValues = true + all { + it.outputs.upToDateWhen { false } + it.testLogging { + events("passed", "skipped", "failed", "standardOut", "standardError") + showStandardStreams = true + } + // The org.gradle.jvmargs property that may be set in gradle.properties does not impact + // the Java heap size when running the Android unit tests. The following property here + // sets the heap size to a size large enough to run the robolectric tests across + // multiple SDK levels. + it.jvmArgs("-Xmx1G") } } } @@ -65,18 +72,18 @@ android { lint { checkAllWarnings = true warningsAsErrors = true - disable 'AndroidGradlePluginVersion', 'GradleDependency', 'InvalidPackage', 'NewerVersionAvailable' + disable.addAll(setOf("AndroidGradlePluginVersion", "GradleDependency", "InvalidPackage", "NewerVersionAvailable")) baseline = file("lint-baseline.xml") } } dependencies { // CameraX core library using the camera2 implementation must use same version number. - def camerax_version = "1.5.3" - implementation("androidx.camera:camera-core:${camerax_version}") - implementation("androidx.camera:camera-camera2:${camerax_version}") - implementation("androidx.camera:camera-lifecycle:${camerax_version}") - implementation("androidx.camera:camera-video:${camerax_version}") + val cameraxVersion = "1.5.3" + implementation("androidx.camera:camera-core:${cameraxVersion}") + implementation("androidx.camera:camera-camera2:${cameraxVersion}") + implementation("androidx.camera:camera-lifecycle:${cameraxVersion}") + implementation("androidx.camera:camera-video:${cameraxVersion}") implementation("com.google.guava:guava:33.5.0-android") testImplementation("junit:junit:4.13.2") testImplementation("org.mockito:mockito-core:5.23.0") diff --git a/packages/camera/camera_android_camerax/android/settings.gradle b/packages/camera/camera_android_camerax/android/settings.gradle deleted file mode 100644 index 613f994165a0..000000000000 --- a/packages/camera/camera_android_camerax/android/settings.gradle +++ /dev/null @@ -1 +0,0 @@ -rootProject.name = 'camera_android_camerax' diff --git a/packages/camera/camera_android_camerax/android/settings.gradle.kts b/packages/camera/camera_android_camerax/android/settings.gradle.kts new file mode 100644 index 000000000000..9d4ef5bade6a --- /dev/null +++ b/packages/camera/camera_android_camerax/android/settings.gradle.kts @@ -0,0 +1 @@ +rootProject.name = "camera_android_camerax" diff --git a/packages/camera/camera_android_camerax/example/lib/camera_controller.dart b/packages/camera/camera_android_camerax/example/lib/camera_controller.dart index ae95d306d52a..7d456043fa4a 100644 --- a/packages/camera/camera_android_camerax/example/lib/camera_controller.dart +++ b/packages/camera/camera_android_camerax/example/lib/camera_controller.dart @@ -898,13 +898,7 @@ class Optional extends IterableBase { const Optional.absent() : _value = null; /// Constructs an Optional of the given [value]. - /// - /// Throws [ArgumentError] if [value] is null. - Optional.of(T value) : _value = value { - // TODO(cbracken): Delete and make this ctor const once mixed-mode - // execution is no longer around. - ArgumentError.checkNotNull(value); - } + const Optional.of(T value) : _value = value; /// Constructs an Optional of the given [value]. /// diff --git a/packages/camera/camera_android_camerax/pigeons/camerax_library.dart b/packages/camera/camera_android_camerax/pigeons/camerax_library.dart index 2aa23c062bce..611157f65248 100644 --- a/packages/camera/camera_android_camerax/pigeons/camerax_library.dart +++ b/packages/camera/camera_android_camerax/pigeons/camerax_library.dart @@ -112,7 +112,7 @@ enum CameraStateType { unknown, } -/// The types (T) properly wrapped to be used as a LiveData. +/// The types (T) properly wrapped to be used as a `LiveData`. enum LiveDataSupportedType { cameraState, zoomState } /// Immutable class for describing the range of two integer values. diff --git a/packages/camera/camera_android_camerax/pubspec.yaml b/packages/camera/camera_android_camerax/pubspec.yaml index 83ccda21ad1f..2dda62c4a153 100644 --- a/packages/camera/camera_android_camerax/pubspec.yaml +++ b/packages/camera/camera_android_camerax/pubspec.yaml @@ -2,7 +2,7 @@ name: camera_android_camerax description: Android implementation of the camera plugin using the CameraX library. repository: https://github.com/flutter/packages/tree/main/packages/camera/camera_android_camerax issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+camera%22 -version: 0.7.1 +version: 0.7.1+2 environment: sdk: ^3.9.0 diff --git a/packages/camera/camera_avfoundation/example/.gitignore b/packages/camera/camera_avfoundation/example/.gitignore new file mode 100644 index 000000000000..3820a95c65c3 --- /dev/null +++ b/packages/camera/camera_avfoundation/example/.gitignore @@ -0,0 +1,45 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.build/ +.buildlog/ +.history +.svn/ +.swiftpm/ +migrate_working_dir/ + +# IntelliJ related +*.iml +*.ipr +*.iws +.idea/ + +# The .vscode folder contains launch configuration and tasks you configure in +# VS Code which you may wish to be included in version control, so this line +# is commented out by default. +#.vscode/ + +# Flutter/Dart/Pub related +**/doc/api/ +**/ios/Flutter/.last_build_id +.dart_tool/ +.flutter-plugins-dependencies +.pub-cache/ +.pub/ +/build/ +/coverage/ + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Android Studio will place build artifacts here +/android/app/debug +/android/app/profile +/android/app/release diff --git a/packages/camera/camera_avfoundation/example/.metadata b/packages/camera/camera_avfoundation/example/.metadata new file mode 100644 index 000000000000..3e79a8d8a334 --- /dev/null +++ b/packages/camera/camera_avfoundation/example/.metadata @@ -0,0 +1,30 @@ +# This file tracks properties of this Flutter project. +# Used by Flutter tool to assess capabilities and perform upgrades etc. +# +# This file should be version controlled and should not be manually edited. + +version: + revision: "ff37bef603469fb030f2b72995ab929ccfc227f0" + channel: "stable" + +project_type: app + +# Tracks metadata for the flutter migrate command +migration: + platforms: + - platform: root + create_revision: ff37bef603469fb030f2b72995ab929ccfc227f0 + base_revision: ff37bef603469fb030f2b72995ab929ccfc227f0 + - platform: ios + create_revision: ff37bef603469fb030f2b72995ab929ccfc227f0 + base_revision: ff37bef603469fb030f2b72995ab929ccfc227f0 + + # User provided section + + # List of Local paths (relative to this file) that should be + # ignored by the migrate tool. + # + # Files that are not part of the templates will be ignored by default. + unmanaged_files: + - 'lib/main.dart' + - 'ios/Runner.xcodeproj/project.pbxproj' diff --git a/packages/camera/camera_avfoundation/example/ios/.gitignore b/packages/camera/camera_avfoundation/example/ios/.gitignore new file mode 100644 index 000000000000..7a7f9873ad7d --- /dev/null +++ b/packages/camera/camera_avfoundation/example/ios/.gitignore @@ -0,0 +1,34 @@ +**/dgph +*.mode1v3 +*.mode2v3 +*.moved-aside +*.pbxuser +*.perspectivev3 +**/*sync/ +.sconsign.dblite +.tags* +**/.vagrant/ +**/DerivedData/ +Icon? +**/Pods/ +**/.symlinks/ +profile +xcuserdata +**/.generated/ +Flutter/App.framework +Flutter/Flutter.framework +Flutter/Flutter.podspec +Flutter/Generated.xcconfig +Flutter/ephemeral/ +Flutter/app.flx +Flutter/app.zip +Flutter/flutter_assets/ +Flutter/flutter_export_environment.sh +ServiceDefinitions.json +Runner/GeneratedPluginRegistrant.* + +# Exceptions to above rules. +!default.mode1v3 +!default.mode2v3 +!default.pbxuser +!default.perspectivev3 diff --git a/packages/camera/camera_avfoundation/example/ios/Flutter/AppFrameworkInfo.plist b/packages/camera/camera_avfoundation/example/ios/Flutter/AppFrameworkInfo.plist index 6fe4034356ac..391a902b2beb 100644 --- a/packages/camera/camera_avfoundation/example/ios/Flutter/AppFrameworkInfo.plist +++ b/packages/camera/camera_avfoundation/example/ios/Flutter/AppFrameworkInfo.plist @@ -20,9 +20,5 @@ ???? CFBundleVersion 1.0 - UIRequiredDeviceCapabilities - - arm64 - diff --git a/packages/camera/camera_avfoundation/example/ios/Runner.xcodeproj/project.pbxproj b/packages/camera/camera_avfoundation/example/ios/Runner.xcodeproj/project.pbxproj index 2776179e27a0..94bbaa417925 100644 --- a/packages/camera/camera_avfoundation/example/ios/Runner.xcodeproj/project.pbxproj +++ b/packages/camera/camera_avfoundation/example/ios/Runner.xcodeproj/project.pbxproj @@ -3,66 +3,65 @@ archiveVersion = 1; classes = { }; - objectVersion = 54; + objectVersion = 60; objects = { /* Begin PBXBuildFile section */ 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; + 335A7B032F6B061D005902FE /* CameraZoomTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335A7AE82F6B061D005902FE /* CameraZoomTests.swift */; }; + 335A7B042F6B061D005902FE /* AvailableCamerasTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335A7AD72F6B061D005902FE /* AvailableCamerasTests.swift */; }; + 335A7B052F6B061D005902FE /* PhotoCaptureTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335A7AFE2F6B061D005902FE /* PhotoCaptureTests.swift */; }; + 335A7B062F6B061D005902FE /* SavePhotoDelegateTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335A7B012F6B061D005902FE /* SavePhotoDelegateTests.swift */; }; + 335A7B072F6B061D005902FE /* MockCameraDeviceDiscoverer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335A7AED2F6B061D005902FE /* MockCameraDeviceDiscoverer.swift */; }; + 335A7B082F6B061D005902FE /* MockFlutterTextureRegistry.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335A7AF92F6B061D005902FE /* MockFlutterTextureRegistry.swift */; }; + 335A7B092F6B061D005902FE /* QueueUtilsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335A7AFF2F6B061D005902FE /* QueueUtilsTests.swift */; }; + 335A7B0A2F6B061D005902FE /* CameraPreviewPauseTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335A7ADF2F6B061D005902FE /* CameraPreviewPauseTests.swift */; }; + 335A7B0B2F6B061D005902FE /* CameraPluginCreateCameraTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335A7ADC2F6B061D005902FE /* CameraPluginCreateCameraTests.swift */; }; + 335A7B0C2F6B061D005902FE /* MockCaptureDevice.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335A7AEF2F6B061D005902FE /* MockCaptureDevice.swift */; }; + 335A7B0D2F6B061D005902FE /* MockWritableData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335A7AFC2F6B061D005902FE /* MockWritableData.swift */; }; + 335A7B0E2F6B061D005902FE /* CameraOrientationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335A7ADA2F6B061D005902FE /* CameraOrientationTests.swift */; }; + 335A7B0F2F6B061D005902FE /* CameraSetFlashModeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335A7AE72F6B061D005902FE /* CameraSetFlashModeTests.swift */; }; + 335A7B102F6B061D005902FE /* CameraSettingsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335A7AE22F6B061D005902FE /* CameraSettingsTests.swift */; }; + 335A7B112F6B061D005902FE /* CameraExposureTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335A7AE42F6B061D005902FE /* CameraExposureTests.swift */; }; + 335A7B122F6B061D005902FE /* CameraMethodChannelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335A7AD92F6B061D005902FE /* CameraMethodChannelTests.swift */; }; + 335A7B132F6B061D005902FE /* MockGlobalEventApi.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335A7AFB2F6B061D005902FE /* MockGlobalEventApi.swift */; }; + 335A7B142F6B061D005902FE /* MockAssetWriter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335A7AE92F6B061D005902FE /* MockAssetWriter.swift */; }; + 335A7B152F6B061D005902FE /* MockCapturePhotoOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335A7AF32F6B061D005902FE /* MockCapturePhotoOutput.swift */; }; + 335A7B162F6B061D005902FE /* CameraSetFocusModeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335A7AE52F6B061D005902FE /* CameraSetFocusModeTests.swift */; }; + 335A7B172F6B061D005902FE /* CameraPluginInitializeCameraTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335A7ADE2F6B061D005902FE /* CameraPluginInitializeCameraTests.swift */; }; + 335A7B182F6B061D005902FE /* CameraPluginDelegatingMethodTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335A7ADD2F6B061D005902FE /* CameraPluginDelegatingMethodTests.swift */; }; + 335A7B192F6B061D005902FE /* MockAssetWriterInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335A7AEA2F6B061D005902FE /* MockAssetWriterInput.swift */; }; + 335A7B1A2F6B061D005902FE /* CameraTestUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335A7AE32F6B061D005902FE /* CameraTestUtils.swift */; }; + 335A7B1B2F6B061D005902FE /* MockAssetWriterInputPixelBufferAdaptor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335A7AEB2F6B061D005902FE /* MockAssetWriterInputPixelBufferAdaptor.swift */; }; + 335A7B1C2F6B061D005902FE /* MockFrameRateRange.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335A7AFA2F6B061D005902FE /* MockFrameRateRange.swift */; }; + 335A7B1D2F6B061D005902FE /* MockDeviceOrientationProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335A7AF62F6B061D005902FE /* MockDeviceOrientationProvider.swift */; }; + 335A7B1E2F6B061D005902FE /* MockCaptureSession.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335A7AF42F6B061D005902FE /* MockCaptureSession.swift */; }; + 335A7B1F2F6B061D005902FE /* CameraPermissionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335A7ADB2F6B061D005902FE /* CameraPermissionTests.swift */; }; + 335A7B202F6B061D005902FE /* MockCaptureDeviceInputFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335A7AF12F6B061D005902FE /* MockCaptureDeviceInputFactory.swift */; }; + 335A7B212F6B061D005902FE /* SampleBufferTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335A7B002F6B061D005902FE /* SampleBufferTests.swift */; }; + 335A7B222F6B061D005902FE /* MockCaptureInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335A7AF22F6B061D005902FE /* MockCaptureInput.swift */; }; + 335A7B232F6B061D005902FE /* CameraSetDeviceOrientationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335A7AE62F6B061D005902FE /* CameraSetDeviceOrientationTests.swift */; }; + 335A7B242F6B061D005902FE /* MockCamera.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335A7AEC2F6B061D005902FE /* MockCamera.swift */; }; + 335A7B252F6B061D005902FE /* MockCaptureDeviceFormat.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335A7AF02F6B061D005902FE /* MockCaptureDeviceFormat.swift */; }; + 335A7B262F6B061D005902FE /* MockFLTCameraPermissionManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335A7AF72F6B061D005902FE /* MockFLTCameraPermissionManager.swift */; }; + 335A7B272F6B061D005902FE /* CameraPropertiesTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335A7AE02F6B061D005902FE /* CameraPropertiesTests.swift */; }; + 335A7B282F6B061D005902FE /* CameraSessionPresetsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335A7AE12F6B061D005902FE /* CameraSessionPresetsTests.swift */; }; + 335A7B292F6B061D005902FE /* MockFlutterBinaryMessenger.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335A7AF82F6B061D005902FE /* MockFlutterBinaryMessenger.swift */; }; + 335A7B2A2F6B061D005902FE /* CameraInitRaceConditionsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335A7AD82F6B061D005902FE /* CameraInitRaceConditionsTests.swift */; }; + 335A7B2B2F6B061D005902FE /* MockCaptureConnection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335A7AEE2F6B061D005902FE /* MockCaptureConnection.swift */; }; + 335A7B2C2F6B061D005902FE /* StreamingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335A7B022F6B061D005902FE /* StreamingTests.swift */; }; + 335A7B2D2F6B061D005902FE /* MockCaptureVideoDataOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335A7AF52F6B061D005902FE /* MockCaptureVideoDataOutput.swift */; }; 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; + 7884E8682EC3CC0700C636F2 /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7884E8672EC3CC0400C636F2 /* SceneDelegate.swift */; }; 78A318202AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage in Frameworks */ = {isa = PBXBuildFile; productRef = 78A3181F2AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage */; }; - 970ADABE2D6740A900EFDCD9 /* MockWritableData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 970ADABD2D6740A900EFDCD9 /* MockWritableData.swift */; }; - 972CA92B2D5A1D8C004B846F /* CameraPropertiesTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 972CA92A2D5A1D8C004B846F /* CameraPropertiesTests.swift */; }; - 972CA92D2D5A28C4004B846F /* QueueUtilsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 972CA92C2D5A28C4004B846F /* QueueUtilsTests.swift */; }; - 977A25202D5A439300931E34 /* AvailableCamerasTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 977A251F2D5A439300931E34 /* AvailableCamerasTests.swift */; }; - 977A25222D5A49EC00931E34 /* FLTCamFocusTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 977A25212D5A49EC00931E34 /* FLTCamFocusTests.swift */; }; - 977A25242D5A511600931E34 /* CameraPermissionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 977A25232D5A511600931E34 /* CameraPermissionTests.swift */; }; - 978296CF2D5F744B0009BDD3 /* PhotoCaptureTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 978296CE2D5F744B0009BDD3 /* PhotoCaptureTests.swift */; }; - 978B8F6F1D3862AE00F588F7 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */; }; - 978D90B42D5F630300CD817E /* StreamingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 978D90B32D5F630300CD817E /* StreamingTests.swift */; }; - 97922B0D2D6380C300A9B4CF /* SampleBufferTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 97922B0C2D6380C300A9B4CF /* SampleBufferTests.swift */; }; - 979B3DFB2D5B6BC7009BDE1A /* ExceptionCatcher.m in Sources */ = {isa = PBXBuildFile; fileRef = 979B3DFA2D5B6BC7009BDE1A /* ExceptionCatcher.m */; }; - 979B3DFE2D5B985B009BDE1A /* CameraInitRaceConditionsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 979B3DFD2D5B985B009BDE1A /* CameraInitRaceConditionsTests.swift */; }; - 979B3E002D5B9E6C009BDE1A /* CameraMethodChannelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 979B3DFF2D5B9E6C009BDE1A /* CameraMethodChannelTests.swift */; }; - 979B3E022D5BA48F009BDE1A /* CameraOrientationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 979B3E012D5BA48F009BDE1A /* CameraOrientationTests.swift */; }; - 97BD4A0E2D5CC5AE00F857D5 /* CameraSettingsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 97BD4A0D2D5CC5AE00F857D5 /* CameraSettingsTests.swift */; }; - 97BD4A102D5CE13500F857D5 /* CameraSessionPresetsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 97BD4A0F2D5CE13500F857D5 /* CameraSessionPresetsTests.swift */; }; - 97C0FFAE2D5E023200A36284 /* SavePhotoDelegateTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 97C0FFAD2D5E023200A36284 /* SavePhotoDelegateTests.swift */; }; - 97C146F31CF9000F007C117D /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 97C146F21CF9000F007C117D /* main.m */; }; 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; - 97DB234D2D566D0700CEFE66 /* CameraPreviewPauseTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 97DB234C2D566D0700CEFE66 /* CameraPreviewPauseTests.swift */; }; - E11D6A8F2D81B81D0031E6C5 /* MockCaptureVideoDataOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = E11D6A8E2D81B81D0031E6C5 /* MockCaptureVideoDataOutput.swift */; }; - E11D6A912D82C7740031E6C5 /* FLTCamExposureTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E11D6A902D82C7740031E6C5 /* FLTCamExposureTests.swift */; }; - E12C4FF62D68C69000515E70 /* CameraPluginDelegatingMethodTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E12C4FF52D68C69000515E70 /* CameraPluginDelegatingMethodTests.swift */; }; - E12C4FF82D68E85500515E70 /* MockFLTCameraPermissionManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = E12C4FF72D68E85500515E70 /* MockFLTCameraPermissionManager.swift */; }; - E142681D2D8483FD0046CBBC /* MockCaptureSession.swift in Sources */ = {isa = PBXBuildFile; fileRef = E142681C2D8483FD0046CBBC /* MockCaptureSession.swift */; }; - E142681F2D8566230046CBBC /* CameraTestUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = E142681E2D8566230046CBBC /* CameraTestUtils.swift */; }; - E142F1362D8587F900824824 /* MockCameraDeviceDiscoverer.swift in Sources */ = {isa = PBXBuildFile; fileRef = E142F1352D8587F900824824 /* MockCameraDeviceDiscoverer.swift */; }; - E142F1382D85919700824824 /* MockDeviceOrientationProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = E142F1372D85919700824824 /* MockDeviceOrientationProvider.swift */; }; - E142F13A2D85940600824824 /* MockCapturePhotoOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = E142F1392D85940600824824 /* MockCapturePhotoOutput.swift */; }; - E142F13C2D8596F100824824 /* MockCaptureDeviceFormat.swift in Sources */ = {isa = PBXBuildFile; fileRef = E142F13B2D8596F100824824 /* MockCaptureDeviceFormat.swift */; }; - E142F13E2D859ADC00824824 /* MockFrameRateRange.swift in Sources */ = {isa = PBXBuildFile; fileRef = E142F13D2D859ADC00824824 /* MockFrameRateRange.swift */; }; - E142F1402D85AD7900824824 /* MockCaptureConnection.swift in Sources */ = {isa = PBXBuildFile; fileRef = E142F13F2D85AD7900824824 /* MockCaptureConnection.swift */; }; - E142F1422D85AFA400824824 /* MockGlobalEventApi.swift in Sources */ = {isa = PBXBuildFile; fileRef = E142F1412D85AFA400824824 /* MockGlobalEventApi.swift */; }; - E15139182D80980900FEE47B /* FLTCamSetDeviceOrientationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E15139172D80980900FEE47B /* FLTCamSetDeviceOrientationTests.swift */; }; - E15BC7E42D86D08700F66474 /* MockFlutterTextureRegistry.swift in Sources */ = {isa = PBXBuildFile; fileRef = E15BC7E32D86D08700F66474 /* MockFlutterTextureRegistry.swift */; }; - E15BC7E62D86D17D00F66474 /* MockFlutterBinaryMessenger.swift in Sources */ = {isa = PBXBuildFile; fileRef = E15BC7E52D86D17D00F66474 /* MockFlutterBinaryMessenger.swift */; }; - E16602952D8471C0003CFE12 /* FLTCamZoomTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E16602942D8471C0003CFE12 /* FLTCamZoomTests.swift */; }; - E1A5F4E32D80259C0005BA64 /* FLTCamSetFlashModeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1A5F4E22D80259C0005BA64 /* FLTCamSetFlashModeTests.swift */; }; - E1ABED6C2D94392500AED9CC /* MockAssetWriter.swift in Sources */ = {isa = PBXBuildFile; fileRef = E15BC7E72D86D29F00F66474 /* MockAssetWriter.swift */; }; - E1ABED6D2D94392700AED9CC /* MockAssetWriterInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = E15BC7E92D86D41F00F66474 /* MockAssetWriterInput.swift */; }; - E1ABED6E2D94392900AED9CC /* MockAssetWriterInputPixelBufferAdaptor.swift in Sources */ = {isa = PBXBuildFile; fileRef = E15BC7EB2D86D50200F66474 /* MockAssetWriterInputPixelBufferAdaptor.swift */; }; - E1ABED6F2D943B2500AED9CC /* MockCaptureDevice.swift in Sources */ = {isa = PBXBuildFile; fileRef = E15BC7ED2D86D85500F66474 /* MockCaptureDevice.swift */; }; - E1ABED722D943DC700AED9CC /* MockCaptureDeviceInputFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1ABED702D943DC700AED9CC /* MockCaptureDeviceInputFactory.swift */; }; - E1ABED732D943DC700AED9CC /* MockCaptureInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1ABED712D943DC700AED9CC /* MockCaptureInput.swift */; }; - E1FFEAAD2D6C8DD700B14107 /* MockCamera.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1FFEAAC2D6C8DD700B14107 /* MockCamera.swift */; }; - E1FFEAAF2D6CDA8C00B14107 /* CameraPluginCreateCameraTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1FFEAAE2D6CDA8C00B14107 /* CameraPluginCreateCameraTests.swift */; }; - E1FFEAB12D6CDE5B00B14107 /* CameraPluginInitializeCameraTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1FFEAB02D6CDE5B00B14107 /* CameraPluginInitializeCameraTests.swift */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ - 03BB766D2665316900CE5A93 /* PBXContainerItemProxy */ = { + 331C8085294A63A400263BE5 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 97C146E61CF9000F007C117D /* Project object */; proxyType = 1; @@ -85,81 +84,68 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ - 03BB76682665316900CE5A93 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; - 03BB766C2665316900CE5A93 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; + 331C8081294A63A400263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 335A7AD72F6B061D005902FE /* AvailableCamerasTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AvailableCamerasTests.swift; sourceTree = ""; }; + 335A7AD82F6B061D005902FE /* CameraInitRaceConditionsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CameraInitRaceConditionsTests.swift; sourceTree = ""; }; + 335A7AD92F6B061D005902FE /* CameraMethodChannelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CameraMethodChannelTests.swift; sourceTree = ""; }; + 335A7ADA2F6B061D005902FE /* CameraOrientationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CameraOrientationTests.swift; sourceTree = ""; }; + 335A7ADB2F6B061D005902FE /* CameraPermissionTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CameraPermissionTests.swift; sourceTree = ""; }; + 335A7ADC2F6B061D005902FE /* CameraPluginCreateCameraTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CameraPluginCreateCameraTests.swift; sourceTree = ""; }; + 335A7ADD2F6B061D005902FE /* CameraPluginDelegatingMethodTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CameraPluginDelegatingMethodTests.swift; sourceTree = ""; }; + 335A7ADE2F6B061D005902FE /* CameraPluginInitializeCameraTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CameraPluginInitializeCameraTests.swift; sourceTree = ""; }; + 335A7ADF2F6B061D005902FE /* CameraPreviewPauseTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CameraPreviewPauseTests.swift; sourceTree = ""; }; + 335A7AE02F6B061D005902FE /* CameraPropertiesTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CameraPropertiesTests.swift; sourceTree = ""; }; + 335A7AE12F6B061D005902FE /* CameraSessionPresetsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CameraSessionPresetsTests.swift; sourceTree = ""; }; + 335A7AE22F6B061D005902FE /* CameraSettingsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CameraSettingsTests.swift; sourceTree = ""; }; + 335A7AE32F6B061D005902FE /* CameraTestUtils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CameraTestUtils.swift; sourceTree = ""; }; + 335A7AE42F6B061D005902FE /* CameraExposureTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CameraExposureTests.swift; sourceTree = ""; }; + 335A7AE52F6B061D005902FE /* CameraSetFocusModeTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CameraSetFocusModeTests.swift; sourceTree = ""; }; + 335A7AE62F6B061D005902FE /* CameraSetDeviceOrientationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CameraSetDeviceOrientationTests.swift; sourceTree = ""; }; + 335A7AE72F6B061D005902FE /* CameraSetFlashModeTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CameraSetFlashModeTests.swift; sourceTree = ""; }; + 335A7AE82F6B061D005902FE /* CameraZoomTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CameraZoomTests.swift; sourceTree = ""; }; + 335A7AE92F6B061D005902FE /* MockAssetWriter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockAssetWriter.swift; sourceTree = ""; }; + 335A7AEA2F6B061D005902FE /* MockAssetWriterInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockAssetWriterInput.swift; sourceTree = ""; }; + 335A7AEB2F6B061D005902FE /* MockAssetWriterInputPixelBufferAdaptor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockAssetWriterInputPixelBufferAdaptor.swift; sourceTree = ""; }; + 335A7AEC2F6B061D005902FE /* MockCamera.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockCamera.swift; sourceTree = ""; }; + 335A7AED2F6B061D005902FE /* MockCameraDeviceDiscoverer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockCameraDeviceDiscoverer.swift; sourceTree = ""; }; + 335A7AEE2F6B061D005902FE /* MockCaptureConnection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockCaptureConnection.swift; sourceTree = ""; }; + 335A7AEF2F6B061D005902FE /* MockCaptureDevice.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockCaptureDevice.swift; sourceTree = ""; }; + 335A7AF02F6B061D005902FE /* MockCaptureDeviceFormat.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockCaptureDeviceFormat.swift; sourceTree = ""; }; + 335A7AF12F6B061D005902FE /* MockCaptureDeviceInputFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockCaptureDeviceInputFactory.swift; sourceTree = ""; }; + 335A7AF22F6B061D005902FE /* MockCaptureInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockCaptureInput.swift; sourceTree = ""; }; + 335A7AF32F6B061D005902FE /* MockCapturePhotoOutput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockCapturePhotoOutput.swift; sourceTree = ""; }; + 335A7AF42F6B061D005902FE /* MockCaptureSession.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockCaptureSession.swift; sourceTree = ""; }; + 335A7AF52F6B061D005902FE /* MockCaptureVideoDataOutput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockCaptureVideoDataOutput.swift; sourceTree = ""; }; + 335A7AF62F6B061D005902FE /* MockDeviceOrientationProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockDeviceOrientationProvider.swift; sourceTree = ""; }; + 335A7AF72F6B061D005902FE /* MockFLTCameraPermissionManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockFLTCameraPermissionManager.swift; sourceTree = ""; }; + 335A7AF82F6B061D005902FE /* MockFlutterBinaryMessenger.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockFlutterBinaryMessenger.swift; sourceTree = ""; }; + 335A7AF92F6B061D005902FE /* MockFlutterTextureRegistry.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockFlutterTextureRegistry.swift; sourceTree = ""; }; + 335A7AFA2F6B061D005902FE /* MockFrameRateRange.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockFrameRateRange.swift; sourceTree = ""; }; + 335A7AFB2F6B061D005902FE /* MockGlobalEventApi.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockGlobalEventApi.swift; sourceTree = ""; }; + 335A7AFC2F6B061D005902FE /* MockWritableData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockWritableData.swift; sourceTree = ""; }; + 335A7AFE2F6B061D005902FE /* PhotoCaptureTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhotoCaptureTests.swift; sourceTree = ""; }; + 335A7AFF2F6B061D005902FE /* QueueUtilsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QueueUtilsTests.swift; sourceTree = ""; }; + 335A7B002F6B061D005902FE /* SampleBufferTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SampleBufferTests.swift; sourceTree = ""; }; + 335A7B012F6B061D005902FE /* SavePhotoDelegateTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SavePhotoDelegateTests.swift; sourceTree = ""; }; + 335A7B022F6B061D005902FE /* StreamingTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StreamingTests.swift; sourceTree = ""; }; 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; - 784666492D4C4C64000A1A5F /* FlutterFramework */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = FlutterFramework; path = Flutter/ephemeral/Packages/.packages/FlutterFramework; sourceTree = ""; }; - 78DABEA22ED26510000E7860 /* camera_avfoundation */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = camera_avfoundation; path = ../../ios/camera_avfoundation; sourceTree = ""; }; + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 7884E8672EC3CC0400C636F2 /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = ""; }; 78E0A7A72DC9AD7400C4905E /* FlutterGeneratedPluginSwiftPackage */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = FlutterGeneratedPluginSwiftPackage; path = Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage; sourceTree = ""; }; 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; - 7AFFD8ED1D35381100E5BB4D /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; - 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; - 970ADABD2D6740A900EFDCD9 /* MockWritableData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockWritableData.swift; sourceTree = ""; }; - 972CA92A2D5A1D8C004B846F /* CameraPropertiesTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CameraPropertiesTests.swift; sourceTree = ""; }; - 972CA92C2D5A28C4004B846F /* QueueUtilsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QueueUtilsTests.swift; sourceTree = ""; }; 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; - 977A251F2D5A439300931E34 /* AvailableCamerasTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AvailableCamerasTests.swift; sourceTree = ""; }; - 977A25212D5A49EC00931E34 /* FLTCamFocusTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FLTCamFocusTests.swift; sourceTree = ""; }; - 977A25232D5A511600931E34 /* CameraPermissionTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CameraPermissionTests.swift; sourceTree = ""; }; - 978296CE2D5F744B0009BDD3 /* PhotoCaptureTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhotoCaptureTests.swift; sourceTree = ""; }; - 978D90B32D5F630300CD817E /* StreamingTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StreamingTests.swift; sourceTree = ""; }; - 97922B0C2D6380C300A9B4CF /* SampleBufferTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SampleBufferTests.swift; sourceTree = ""; }; - 979B3DF92D5B6BA2009BDE1A /* ExceptionCatcher.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ExceptionCatcher.h; sourceTree = ""; }; - 979B3DFA2D5B6BC7009BDE1A /* ExceptionCatcher.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ExceptionCatcher.m; sourceTree = ""; }; - 979B3DFC2D5B985B009BDE1A /* RunnerTests-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "RunnerTests-Bridging-Header.h"; sourceTree = ""; }; - 979B3DFD2D5B985B009BDE1A /* CameraInitRaceConditionsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CameraInitRaceConditionsTests.swift; sourceTree = ""; }; - 979B3DFF2D5B9E6C009BDE1A /* CameraMethodChannelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CameraMethodChannelTests.swift; sourceTree = ""; }; - 979B3E012D5BA48F009BDE1A /* CameraOrientationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CameraOrientationTests.swift; sourceTree = ""; }; - 97BD4A0D2D5CC5AE00F857D5 /* CameraSettingsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CameraSettingsTests.swift; sourceTree = ""; }; - 97BD4A0F2D5CE13500F857D5 /* CameraSessionPresetsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CameraSessionPresetsTests.swift; sourceTree = ""; }; - 97C0FFAD2D5E023200A36284 /* SavePhotoDelegateTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SavePhotoDelegateTests.swift; sourceTree = ""; }; 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; - 97C146F21CF9000F007C117D /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 97DB234C2D566D0700CEFE66 /* CameraPreviewPauseTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CameraPreviewPauseTests.swift; sourceTree = ""; }; - E11D6A8E2D81B81D0031E6C5 /* MockCaptureVideoDataOutput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockCaptureVideoDataOutput.swift; sourceTree = ""; }; - E11D6A902D82C7740031E6C5 /* FLTCamExposureTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FLTCamExposureTests.swift; sourceTree = ""; }; - E12C4FF52D68C69000515E70 /* CameraPluginDelegatingMethodTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CameraPluginDelegatingMethodTests.swift; sourceTree = ""; }; - E12C4FF72D68E85500515E70 /* MockFLTCameraPermissionManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockFLTCameraPermissionManager.swift; sourceTree = ""; }; - E142681C2D8483FD0046CBBC /* MockCaptureSession.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockCaptureSession.swift; sourceTree = ""; }; - E142681E2D8566230046CBBC /* CameraTestUtils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CameraTestUtils.swift; sourceTree = ""; }; - E142F1352D8587F900824824 /* MockCameraDeviceDiscoverer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockCameraDeviceDiscoverer.swift; sourceTree = ""; }; - E142F1372D85919700824824 /* MockDeviceOrientationProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockDeviceOrientationProvider.swift; sourceTree = ""; }; - E142F1392D85940600824824 /* MockCapturePhotoOutput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockCapturePhotoOutput.swift; sourceTree = ""; }; - E142F13B2D8596F100824824 /* MockCaptureDeviceFormat.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockCaptureDeviceFormat.swift; sourceTree = ""; }; - E142F13D2D859ADC00824824 /* MockFrameRateRange.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockFrameRateRange.swift; sourceTree = ""; }; - E142F13F2D85AD7900824824 /* MockCaptureConnection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockCaptureConnection.swift; sourceTree = ""; }; - E142F1412D85AFA400824824 /* MockGlobalEventApi.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockGlobalEventApi.swift; sourceTree = ""; }; - E15139172D80980900FEE47B /* FLTCamSetDeviceOrientationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FLTCamSetDeviceOrientationTests.swift; sourceTree = ""; }; - E15BC7E32D86D08700F66474 /* MockFlutterTextureRegistry.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockFlutterTextureRegistry.swift; sourceTree = ""; }; - E15BC7E52D86D17D00F66474 /* MockFlutterBinaryMessenger.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockFlutterBinaryMessenger.swift; sourceTree = ""; }; - E15BC7E72D86D29F00F66474 /* MockAssetWriter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockAssetWriter.swift; sourceTree = ""; }; - E15BC7E92D86D41F00F66474 /* MockAssetWriterInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockAssetWriterInput.swift; sourceTree = ""; }; - E15BC7EB2D86D50200F66474 /* MockAssetWriterInputPixelBufferAdaptor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockAssetWriterInputPixelBufferAdaptor.swift; sourceTree = ""; }; - E15BC7ED2D86D85500F66474 /* MockCaptureDevice.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockCaptureDevice.swift; sourceTree = ""; }; - E16602942D8471C0003CFE12 /* FLTCamZoomTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FLTCamZoomTests.swift; sourceTree = ""; }; - E1A5F4E22D80259C0005BA64 /* FLTCamSetFlashModeTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FLTCamSetFlashModeTests.swift; sourceTree = ""; }; - E1ABED702D943DC700AED9CC /* MockCaptureDeviceInputFactory.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MockCaptureDeviceInputFactory.swift; sourceTree = ""; }; - E1ABED712D943DC700AED9CC /* MockCaptureInput.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MockCaptureInput.swift; sourceTree = ""; }; - E1FFEAAC2D6C8DD700B14107 /* MockCamera.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockCamera.swift; sourceTree = ""; }; - E1FFEAAE2D6CDA8C00B14107 /* CameraPluginCreateCameraTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CameraPluginCreateCameraTests.swift; sourceTree = ""; }; - E1FFEAB02D6CDE5B00B14107 /* CameraPluginInitializeCameraTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CameraPluginInitializeCameraTests.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ - 03BB76652665316900CE5A93 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; 97C146EB1CF9000F007C117D /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; @@ -171,64 +157,60 @@ /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ - 03BB76692665316900CE5A93 /* RunnerTests */ = { + 331C8082294A63A400263BE5 /* RunnerTests */ = { isa = PBXGroup; children = ( - 7F29EB3F2D281C6D00740257 /* Mocks */, - 03BB766C2665316900CE5A93 /* Info.plist */, - E142681E2D8566230046CBBC /* CameraTestUtils.swift */, - 979B3DF92D5B6BA2009BDE1A /* ExceptionCatcher.h */, - 979B3DFA2D5B6BC7009BDE1A /* ExceptionCatcher.m */, - 979B3DFC2D5B985B009BDE1A /* RunnerTests-Bridging-Header.h */, - 979B3DFD2D5B985B009BDE1A /* CameraInitRaceConditionsTests.swift */, - 979B3DFF2D5B9E6C009BDE1A /* CameraMethodChannelTests.swift */, - 979B3E012D5BA48F009BDE1A /* CameraOrientationTests.swift */, - 97BD4A0D2D5CC5AE00F857D5 /* CameraSettingsTests.swift */, - 97BD4A0F2D5CE13500F857D5 /* CameraSessionPresetsTests.swift */, - 97DB234C2D566D0700CEFE66 /* CameraPreviewPauseTests.swift */, - 972CA92A2D5A1D8C004B846F /* CameraPropertiesTests.swift */, - 972CA92C2D5A28C4004B846F /* QueueUtilsTests.swift */, - 977A251F2D5A439300931E34 /* AvailableCamerasTests.swift */, - 977A25232D5A511600931E34 /* CameraPermissionTests.swift */, - 97C0FFAD2D5E023200A36284 /* SavePhotoDelegateTests.swift */, - 978D90B32D5F630300CD817E /* StreamingTests.swift */, - 97922B0C2D6380C300A9B4CF /* SampleBufferTests.swift */, - 978296CE2D5F744B0009BDD3 /* PhotoCaptureTests.swift */, - E12C4FF52D68C69000515E70 /* CameraPluginDelegatingMethodTests.swift */, - E1FFEAAE2D6CDA8C00B14107 /* CameraPluginCreateCameraTests.swift */, - E1FFEAB02D6CDE5B00B14107 /* CameraPluginInitializeCameraTests.swift */, - E11D6A902D82C7740031E6C5 /* FLTCamExposureTests.swift */, - 977A25212D5A49EC00931E34 /* FLTCamFocusTests.swift */, - E1A5F4E22D80259C0005BA64 /* FLTCamSetFlashModeTests.swift */, - E16602942D8471C0003CFE12 /* FLTCamZoomTests.swift */, - E15139172D80980900FEE47B /* FLTCamSetDeviceOrientationTests.swift */, + 335A7AD72F6B061D005902FE /* AvailableCamerasTests.swift */, + 335A7AE42F6B061D005902FE /* CameraExposureTests.swift */, + 335A7AD82F6B061D005902FE /* CameraInitRaceConditionsTests.swift */, + 335A7AE52F6B061D005902FE /* CameraSetFocusModeTests.swift */, + 335A7AD92F6B061D005902FE /* CameraMethodChannelTests.swift */, + 335A7ADA2F6B061D005902FE /* CameraOrientationTests.swift */, + 335A7ADB2F6B061D005902FE /* CameraPermissionTests.swift */, + 335A7ADC2F6B061D005902FE /* CameraPluginCreateCameraTests.swift */, + 335A7ADD2F6B061D005902FE /* CameraPluginDelegatingMethodTests.swift */, + 335A7ADE2F6B061D005902FE /* CameraPluginInitializeCameraTests.swift */, + 335A7ADF2F6B061D005902FE /* CameraPreviewPauseTests.swift */, + 335A7AE02F6B061D005902FE /* CameraPropertiesTests.swift */, + 335A7AE12F6B061D005902FE /* CameraSessionPresetsTests.swift */, + 335A7AE62F6B061D005902FE /* CameraSetDeviceOrientationTests.swift */, + 335A7AE72F6B061D005902FE /* CameraSetFlashModeTests.swift */, + 335A7AE22F6B061D005902FE /* CameraSettingsTests.swift */, + 335A7AE32F6B061D005902FE /* CameraTestUtils.swift */, + 335A7AE82F6B061D005902FE /* CameraZoomTests.swift */, + 335A7AFE2F6B061D005902FE /* PhotoCaptureTests.swift */, + 335A7AFF2F6B061D005902FE /* QueueUtilsTests.swift */, + 335A7B002F6B061D005902FE /* SampleBufferTests.swift */, + 335A7B012F6B061D005902FE /* SavePhotoDelegateTests.swift */, + 335A7B022F6B061D005902FE /* StreamingTests.swift */, + 335A7AFD2F6B061D005902FE /* Mocks */, ); path = RunnerTests; sourceTree = ""; }; - 7F29EB3F2D281C6D00740257 /* Mocks */ = { + 335A7AFD2F6B061D005902FE /* Mocks */ = { isa = PBXGroup; children = ( - E15BC7E72D86D29F00F66474 /* MockAssetWriter.swift */, - E15BC7E92D86D41F00F66474 /* MockAssetWriterInput.swift */, - E15BC7EB2D86D50200F66474 /* MockAssetWriterInputPixelBufferAdaptor.swift */, - E15BC7E52D86D17D00F66474 /* MockFlutterBinaryMessenger.swift */, - E15BC7E32D86D08700F66474 /* MockFlutterTextureRegistry.swift */, - E142F1412D85AFA400824824 /* MockGlobalEventApi.swift */, - E15BC7ED2D86D85500F66474 /* MockCaptureDevice.swift */, - E1ABED702D943DC700AED9CC /* MockCaptureDeviceInputFactory.swift */, - E1ABED712D943DC700AED9CC /* MockCaptureInput.swift */, - E142F13F2D85AD7900824824 /* MockCaptureConnection.swift */, - E142F13B2D8596F100824824 /* MockCaptureDeviceFormat.swift */, - E142F13D2D859ADC00824824 /* MockFrameRateRange.swift */, - E142F1392D85940600824824 /* MockCapturePhotoOutput.swift */, - E142F1372D85919700824824 /* MockDeviceOrientationProvider.swift */, - E142F1352D8587F900824824 /* MockCameraDeviceDiscoverer.swift */, - E1FFEAAC2D6C8DD700B14107 /* MockCamera.swift */, - E12C4FF72D68E85500515E70 /* MockFLTCameraPermissionManager.swift */, - 970ADABD2D6740A900EFDCD9 /* MockWritableData.swift */, - E11D6A8E2D81B81D0031E6C5 /* MockCaptureVideoDataOutput.swift */, - E142681C2D8483FD0046CBBC /* MockCaptureSession.swift */, + 335A7AE92F6B061D005902FE /* MockAssetWriter.swift */, + 335A7AEA2F6B061D005902FE /* MockAssetWriterInput.swift */, + 335A7AEB2F6B061D005902FE /* MockAssetWriterInputPixelBufferAdaptor.swift */, + 335A7AEC2F6B061D005902FE /* MockCamera.swift */, + 335A7AED2F6B061D005902FE /* MockCameraDeviceDiscoverer.swift */, + 335A7AEE2F6B061D005902FE /* MockCaptureConnection.swift */, + 335A7AEF2F6B061D005902FE /* MockCaptureDevice.swift */, + 335A7AF02F6B061D005902FE /* MockCaptureDeviceFormat.swift */, + 335A7AF12F6B061D005902FE /* MockCaptureDeviceInputFactory.swift */, + 335A7AF22F6B061D005902FE /* MockCaptureInput.swift */, + 335A7AF32F6B061D005902FE /* MockCapturePhotoOutput.swift */, + 335A7AF42F6B061D005902FE /* MockCaptureSession.swift */, + 335A7AF52F6B061D005902FE /* MockCaptureVideoDataOutput.swift */, + 335A7AF62F6B061D005902FE /* MockDeviceOrientationProvider.swift */, + 335A7AF72F6B061D005902FE /* MockFLTCameraPermissionManager.swift */, + 335A7AF82F6B061D005902FE /* MockFlutterBinaryMessenger.swift */, + 335A7AF92F6B061D005902FE /* MockFlutterTextureRegistry.swift */, + 335A7AFA2F6B061D005902FE /* MockFrameRateRange.swift */, + 335A7AFB2F6B061D005902FE /* MockGlobalEventApi.swift */, + 335A7AFC2F6B061D005902FE /* MockWritableData.swift */, ); path = Mocks; sourceTree = ""; @@ -236,8 +218,6 @@ 9740EEB11CF90186004384FC /* Flutter */ = { isa = PBXGroup; children = ( - 78DABEA22ED26510000E7860 /* camera_avfoundation */, - 784666492D4C4C64000A1A5F /* FlutterFramework */, 78E0A7A72DC9AD7400C4905E /* FlutterGeneratedPluginSwiftPackage */, 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, 9740EEB21CF90195004384FC /* Debug.xcconfig */, @@ -252,9 +232,8 @@ children = ( 9740EEB11CF90186004384FC /* Flutter */, 97C146F01CF9000F007C117D /* Runner */, - 03BB76692665316900CE5A93 /* RunnerTests */, 97C146EF1CF9000F007C117D /* Products */, - FD386F00E98D73419C929072 /* Pods */, + 331C8082294A63A400263BE5 /* RunnerTests */, ); sourceTree = ""; }; @@ -262,7 +241,7 @@ isa = PBXGroup; children = ( 97C146EE1CF9000F007C117D /* Runner.app */, - 03BB76682665316900CE5A93 /* RunnerTests.xctest */, + 331C8081294A63A400263BE5 /* RunnerTests.xctest */, ); name = Products; sourceTree = ""; @@ -270,53 +249,37 @@ 97C146F01CF9000F007C117D /* Runner */ = { isa = PBXGroup; children = ( - 7AFFD8ED1D35381100E5BB4D /* AppDelegate.h */, - 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */, 97C146FA1CF9000F007C117D /* Main.storyboard */, 97C146FD1CF9000F007C117D /* Assets.xcassets */, 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, 97C147021CF9000F007C117D /* Info.plist */, - 97C146F11CF9000F007C117D /* Supporting Files */, 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 7884E8672EC3CC0400C636F2 /* SceneDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, ); path = Runner; sourceTree = ""; }; - 97C146F11CF9000F007C117D /* Supporting Files */ = { - isa = PBXGroup; - children = ( - 97C146F21CF9000F007C117D /* main.m */, - ); - name = "Supporting Files"; - sourceTree = ""; - }; - FD386F00E98D73419C929072 /* Pods */ = { - isa = PBXGroup; - children = ( - ); - path = Pods; - sourceTree = ""; - }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ - 03BB76672665316900CE5A93 /* RunnerTests */ = { + 331C8080294A63A400263BE5 /* RunnerTests */ = { isa = PBXNativeTarget; - buildConfigurationList = 03BB76712665316900CE5A93 /* Build configuration list for PBXNativeTarget "RunnerTests" */; + buildConfigurationList = 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */; buildPhases = ( - 03BB76642665316900CE5A93 /* Sources */, - 03BB76652665316900CE5A93 /* Frameworks */, - 03BB76662665316900CE5A93 /* Resources */, + 331C807D294A63A400263BE5 /* Sources */, + 331C807F294A63A400263BE5 /* Resources */, ); buildRules = ( ); dependencies = ( - 03BB766E2665316900CE5A93 /* PBXTargetDependency */, + 331C8086294A63A400263BE5 /* PBXTargetDependency */, ); name = RunnerTests; - productName = camera_exampleTests; - productReference = 03BB76682665316900CE5A93 /* RunnerTests.xctest */; + productName = RunnerTests; + productReference = 331C8081294A63A400263BE5 /* RunnerTests.xctest */; productType = "com.apple.product-type.bundle.unit-test"; }; 97C146ED1CF9000F007C117D /* Runner */ = { @@ -348,22 +311,22 @@ 97C146E61CF9000F007C117D /* Project object */ = { isa = PBXProject; attributes = { + BuildIndependentTargetsInParallel = YES; LastUpgradeCheck = 1510; - ORGANIZATIONNAME = "The Flutter Authors"; + ORGANIZATIONNAME = ""; TargetAttributes = { - 03BB76672665316900CE5A93 = { - CreatedOnToolsVersion = 12.5; - LastSwiftMigration = 1540; - ProvisioningStyle = Automatic; + 331C8080294A63A400263BE5 = { + CreatedOnToolsVersion = 14.0; TestTargetID = 97C146ED1CF9000F007C117D; }; 97C146ED1CF9000F007C117D = { CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1100; }; }; }; buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; - compatibilityVersion = "Xcode 3.2"; + compatibilityVersion = "Xcode 9.3"; developmentRegion = en; hasScannedForEncodings = 0; knownRegions = ( @@ -372,20 +335,20 @@ ); mainGroup = 97C146E51CF9000F007C117D; packageReferences = ( - 781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "FlutterGeneratedPluginSwiftPackage" */, + 781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage" */, ); productRefGroup = 97C146EF1CF9000F007C117D /* Products */; projectDirPath = ""; projectRoot = ""; targets = ( 97C146ED1CF9000F007C117D /* Runner */, - 03BB76672665316900CE5A93 /* RunnerTests */, + 331C8080294A63A400263BE5 /* RunnerTests */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ - 03BB76662665316900CE5A93 /* Resources */ = { + 331C807F294A63A400263BE5 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( @@ -440,54 +403,53 @@ /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ - 03BB76642665316900CE5A93 /* Sources */ = { + 331C807D294A63A400263BE5 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - E11D6A912D82C7740031E6C5 /* FLTCamExposureTests.swift in Sources */, - 97BD4A0E2D5CC5AE00F857D5 /* CameraSettingsTests.swift in Sources */, - E142F1422D85AFA400824824 /* MockGlobalEventApi.swift in Sources */, - 972CA92D2D5A28C4004B846F /* QueueUtilsTests.swift in Sources */, - E1FFEAB12D6CDE5B00B14107 /* CameraPluginInitializeCameraTests.swift in Sources */, - E142F1362D8587F900824824 /* MockCameraDeviceDiscoverer.swift in Sources */, - 979B3DFB2D5B6BC7009BDE1A /* ExceptionCatcher.m in Sources */, - E1ABED6E2D94392900AED9CC /* MockAssetWriterInputPixelBufferAdaptor.swift in Sources */, - E1ABED6C2D94392500AED9CC /* MockAssetWriter.swift in Sources */, - E1A5F4E32D80259C0005BA64 /* FLTCamSetFlashModeTests.swift in Sources */, - E1ABED6D2D94392700AED9CC /* MockAssetWriterInput.swift in Sources */, - 977A25242D5A511600931E34 /* CameraPermissionTests.swift in Sources */, - 970ADABE2D6740A900EFDCD9 /* MockWritableData.swift in Sources */, - 979B3DFE2D5B985B009BDE1A /* CameraInitRaceConditionsTests.swift in Sources */, - E142F13A2D85940600824824 /* MockCapturePhotoOutput.swift in Sources */, - E12C4FF82D68E85500515E70 /* MockFLTCameraPermissionManager.swift in Sources */, - 97922B0D2D6380C300A9B4CF /* SampleBufferTests.swift in Sources */, - E142681D2D8483FD0046CBBC /* MockCaptureSession.swift in Sources */, - E15139182D80980900FEE47B /* FLTCamSetDeviceOrientationTests.swift in Sources */, - 972CA92B2D5A1D8C004B846F /* CameraPropertiesTests.swift in Sources */, - E15BC7E42D86D08700F66474 /* MockFlutterTextureRegistry.swift in Sources */, - 978296CF2D5F744B0009BDD3 /* PhotoCaptureTests.swift in Sources */, - 979B3E002D5B9E6C009BDE1A /* CameraMethodChannelTests.swift in Sources */, - E142F13C2D8596F100824824 /* MockCaptureDeviceFormat.swift in Sources */, - E1FFEAAF2D6CDA8C00B14107 /* CameraPluginCreateCameraTests.swift in Sources */, - E142F13E2D859ADC00824824 /* MockFrameRateRange.swift in Sources */, - 97DB234D2D566D0700CEFE66 /* CameraPreviewPauseTests.swift in Sources */, - E1ABED732D943DC700AED9CC /* MockCaptureInput.swift in Sources */, - E1ABED6F2D943B2500AED9CC /* MockCaptureDevice.swift in Sources */, - E1ABED722D943DC700AED9CC /* MockCaptureDeviceInputFactory.swift in Sources */, - 977A25202D5A439300931E34 /* AvailableCamerasTests.swift in Sources */, - E142681F2D8566230046CBBC /* CameraTestUtils.swift in Sources */, - E1FFEAAD2D6C8DD700B14107 /* MockCamera.swift in Sources */, - E16602952D8471C0003CFE12 /* FLTCamZoomTests.swift in Sources */, - 97BD4A102D5CE13500F857D5 /* CameraSessionPresetsTests.swift in Sources */, - 979B3E022D5BA48F009BDE1A /* CameraOrientationTests.swift in Sources */, - E12C4FF62D68C69000515E70 /* CameraPluginDelegatingMethodTests.swift in Sources */, - 977A25222D5A49EC00931E34 /* FLTCamFocusTests.swift in Sources */, - 978D90B42D5F630300CD817E /* StreamingTests.swift in Sources */, - E142F1382D85919700824824 /* MockDeviceOrientationProvider.swift in Sources */, - E11D6A8F2D81B81D0031E6C5 /* MockCaptureVideoDataOutput.swift in Sources */, - E142F1402D85AD7900824824 /* MockCaptureConnection.swift in Sources */, - E15BC7E62D86D17D00F66474 /* MockFlutterBinaryMessenger.swift in Sources */, - 97C0FFAE2D5E023200A36284 /* SavePhotoDelegateTests.swift in Sources */, + 335A7B032F6B061D005902FE /* CameraZoomTests.swift in Sources */, + 335A7B042F6B061D005902FE /* AvailableCamerasTests.swift in Sources */, + 335A7B052F6B061D005902FE /* PhotoCaptureTests.swift in Sources */, + 335A7B062F6B061D005902FE /* SavePhotoDelegateTests.swift in Sources */, + 335A7B072F6B061D005902FE /* MockCameraDeviceDiscoverer.swift in Sources */, + 335A7B082F6B061D005902FE /* MockFlutterTextureRegistry.swift in Sources */, + 335A7B092F6B061D005902FE /* QueueUtilsTests.swift in Sources */, + 335A7B0A2F6B061D005902FE /* CameraPreviewPauseTests.swift in Sources */, + 335A7B0B2F6B061D005902FE /* CameraPluginCreateCameraTests.swift in Sources */, + 335A7B0C2F6B061D005902FE /* MockCaptureDevice.swift in Sources */, + 335A7B0D2F6B061D005902FE /* MockWritableData.swift in Sources */, + 335A7B0E2F6B061D005902FE /* CameraOrientationTests.swift in Sources */, + 335A7B0F2F6B061D005902FE /* CameraSetFlashModeTests.swift in Sources */, + 335A7B102F6B061D005902FE /* CameraSettingsTests.swift in Sources */, + 335A7B112F6B061D005902FE /* CameraExposureTests.swift in Sources */, + 335A7B122F6B061D005902FE /* CameraMethodChannelTests.swift in Sources */, + 335A7B132F6B061D005902FE /* MockGlobalEventApi.swift in Sources */, + 335A7B142F6B061D005902FE /* MockAssetWriter.swift in Sources */, + 335A7B152F6B061D005902FE /* MockCapturePhotoOutput.swift in Sources */, + 335A7B162F6B061D005902FE /* CameraSetFocusModeTests.swift in Sources */, + 335A7B172F6B061D005902FE /* CameraPluginInitializeCameraTests.swift in Sources */, + 335A7B182F6B061D005902FE /* CameraPluginDelegatingMethodTests.swift in Sources */, + 335A7B192F6B061D005902FE /* MockAssetWriterInput.swift in Sources */, + 335A7B1A2F6B061D005902FE /* CameraTestUtils.swift in Sources */, + 335A7B1B2F6B061D005902FE /* MockAssetWriterInputPixelBufferAdaptor.swift in Sources */, + 335A7B1C2F6B061D005902FE /* MockFrameRateRange.swift in Sources */, + 335A7B1D2F6B061D005902FE /* MockDeviceOrientationProvider.swift in Sources */, + 335A7B1E2F6B061D005902FE /* MockCaptureSession.swift in Sources */, + 335A7B1F2F6B061D005902FE /* CameraPermissionTests.swift in Sources */, + 335A7B202F6B061D005902FE /* MockCaptureDeviceInputFactory.swift in Sources */, + 335A7B212F6B061D005902FE /* SampleBufferTests.swift in Sources */, + 335A7B222F6B061D005902FE /* MockCaptureInput.swift in Sources */, + 335A7B232F6B061D005902FE /* CameraSetDeviceOrientationTests.swift in Sources */, + 335A7B242F6B061D005902FE /* MockCamera.swift in Sources */, + 335A7B252F6B061D005902FE /* MockCaptureDeviceFormat.swift in Sources */, + 335A7B262F6B061D005902FE /* MockFLTCameraPermissionManager.swift in Sources */, + 335A7B272F6B061D005902FE /* CameraPropertiesTests.swift in Sources */, + 335A7B282F6B061D005902FE /* CameraSessionPresetsTests.swift in Sources */, + 335A7B292F6B061D005902FE /* MockFlutterBinaryMessenger.swift in Sources */, + 335A7B2A2F6B061D005902FE /* CameraInitRaceConditionsTests.swift in Sources */, + 335A7B2B2F6B061D005902FE /* MockCaptureConnection.swift in Sources */, + 335A7B2C2F6B061D005902FE /* StreamingTests.swift in Sources */, + 335A7B2D2F6B061D005902FE /* MockCaptureVideoDataOutput.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -495,19 +457,19 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 978B8F6F1D3862AE00F588F7 /* AppDelegate.m in Sources */, - 97C146F31CF9000F007C117D /* main.m in Sources */, + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + 7884E8682EC3CC0700C636F2 /* SceneDelegate.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ - 03BB766E2665316900CE5A93 /* PBXTargetDependency */ = { + 331C8086294A63A400263BE5 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 97C146ED1CF9000F007C117D /* Runner */; - targetProxy = 03BB766D2665316900CE5A93 /* PBXContainerItemProxy */; + targetProxy = 331C8085294A63A400263BE5 /* PBXContainerItemProxy */; }; /* End PBXTargetDependency section */ @@ -531,73 +493,131 @@ /* End PBXVariantGroup section */ /* Begin XCBuildConfiguration section */ - 03BB766F2665316900CE5A93 /* Debug */ = { + 249021D3217E4FDB00AE95B9 /* Profile */ = { isa = XCBuildConfiguration; buildSettings = { - BUNDLE_LOADER = "$(TEST_HOST)"; - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_WEAK = YES; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO; - CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; - CODE_SIGN_STYLE = Automatic; - GCC_C_LANGUAGE_STANDARD = gnu11; - INFOPLIST_FILE = RunnerTests/Info.plist; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 13.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Profile; + }; + 249021D4217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = Runner/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", - "@loader_path/Frameworks", ); - MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; - MTL_FAST_MATH = YES; - PRODUCT_BUNDLE_IDENTIFIER = "dev.flutter.plugins.cameraExample.camera-exampleTests"; + PRODUCT_BUNDLE_IDENTIFIER = dev.flutter.cameraExample; PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_OBJC_BRIDGING_HEADER = "RunnerTests/RunnerTests-Bridging-Header.h"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 331C8088294A63A400263BE5 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = dev.flutter.cameraExample.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; - TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/Runner"; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; }; name = Debug; }; - 03BB76702665316900CE5A93 /* Release */ = { + 331C8089294A63A400263BE5 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_WEAK = YES; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO; - CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CODE_SIGN_STYLE = Automatic; - GCC_C_LANGUAGE_STANDARD = gnu11; - INFOPLIST_FILE = RunnerTests/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 13.0; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - "@loader_path/Frameworks", - ); - MTL_FAST_MATH = YES; - PRODUCT_BUNDLE_IDENTIFIER = "dev.flutter.plugins.cameraExample.camera-exampleTests"; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = dev.flutter.cameraExample.RunnerTests; PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_OBJC_BRIDGING_HEADER = "RunnerTests/RunnerTests-Bridging-Header.h"; SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; - TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/Runner"; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; }; name = Release; }; + 331C808A294A63A400263BE5 /* Profile */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = dev.flutter.cameraExample.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; + }; + name = Profile; + }; 97C147031CF9000F007C117D /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; CLANG_ANALYZER_NONNULL = YES; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; @@ -627,6 +647,7 @@ DEBUG_INFORMATION_FORMAT = dwarf; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_DYNAMIC_NO_PIC = NO; GCC_NO_COMMON_BLOCKS = YES; @@ -653,7 +674,7 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; CLANG_ANALYZER_NONNULL = YES; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; @@ -683,6 +704,7 @@ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; @@ -694,6 +716,9 @@ IPHONEOS_DEPLOYMENT_TARGET = 13.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; TARGETED_DEVICE_FAMILY = "1,2"; VALIDATE_PRODUCT = YES; }; @@ -704,22 +729,20 @@ baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; ENABLE_BITCODE = NO; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Flutter", - ); INFOPLIST_FILE = Runner/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", ); - LIBRARY_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Flutter", - ); - PRODUCT_BUNDLE_IDENTIFIER = dev.flutter.plugins.cameraExample; + PRODUCT_BUNDLE_IDENTIFIER = dev.flutter.cameraExample; PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; }; name = Debug; }; @@ -728,33 +751,31 @@ baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; ENABLE_BITCODE = NO; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Flutter", - ); INFOPLIST_FILE = Runner/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", ); - LIBRARY_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Flutter", - ); - PRODUCT_BUNDLE_IDENTIFIER = dev.flutter.plugins.cameraExample; + PRODUCT_BUNDLE_IDENTIFIER = dev.flutter.cameraExample; PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; }; name = Release; }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ - 03BB76712665316900CE5A93 /* Build configuration list for PBXNativeTarget "RunnerTests" */ = { + 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */ = { isa = XCConfigurationList; buildConfigurations = ( - 03BB766F2665316900CE5A93 /* Debug */, - 03BB76702665316900CE5A93 /* Release */, + 331C8088294A63A400263BE5 /* Debug */, + 331C8089294A63A400263BE5 /* Release */, + 331C808A294A63A400263BE5 /* Profile */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; @@ -764,6 +785,7 @@ buildConfigurations = ( 97C147031CF9000F007C117D /* Debug */, 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; @@ -773,6 +795,7 @@ buildConfigurations = ( 97C147061CF9000F007C117D /* Debug */, 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; @@ -780,7 +803,7 @@ /* End XCConfigurationList section */ /* Begin XCLocalSwiftPackageReference section */ - 781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "FlutterGeneratedPluginSwiftPackage" */ = { + 781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage" */ = { isa = XCLocalSwiftPackageReference; relativePath = Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage; }; diff --git a/packages/camera/camera_avfoundation/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/packages/camera/camera_avfoundation/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000000..18d981003d68 --- /dev/null +++ b/packages/camera/camera_avfoundation/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/packages/camera/camera_avfoundation/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/packages/camera/camera_avfoundation/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 000000000000..f9b0d7c5ea15 --- /dev/null +++ b/packages/camera/camera_avfoundation/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + PreviewsEnabled + + + diff --git a/packages/camera/camera_avfoundation/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/packages/camera/camera_avfoundation/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index ba0c5508103c..c3fedb29c990 100644 --- a/packages/camera/camera_avfoundation/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/packages/camera/camera_avfoundation/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -44,6 +44,7 @@ buildConfiguration = "Debug" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" + customLLDBInitFile = "$(SRCROOT)/Flutter/ephemeral/flutter_lldbinit" shouldUseLaunchSchemeArgsEnv = "YES"> + skipped = "NO" + parallelizable = "YES"> @@ -71,6 +73,7 @@ buildConfiguration = "Debug" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" + customLLDBInitFile = "$(SRCROOT)/Flutter/ephemeral/flutter_lldbinit" launchStyle = "0" useCustomWorkingDirectory = "NO" ignoresPersistentStateOnLaunch = "NO" @@ -88,16 +91,9 @@ ReferencedContainer = "container:Runner.xcodeproj"> - - - - - - diff --git a/packages/camera/camera_avfoundation/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/packages/camera/camera_avfoundation/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 000000000000..f9b0d7c5ea15 --- /dev/null +++ b/packages/camera/camera_avfoundation/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + PreviewsEnabled + + + diff --git a/packages/camera/camera_avfoundation/example/ios/Runner/AppDelegate.h b/packages/camera/camera_avfoundation/example/ios/Runner/AppDelegate.h deleted file mode 100644 index 721cca1e11bb..000000000000 --- a/packages/camera/camera_avfoundation/example/ios/Runner/AppDelegate.h +++ /dev/null @@ -1,10 +0,0 @@ -// Copyright 2013 The Flutter Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#import -#import - -@interface AppDelegate : FlutterAppDelegate - -@end diff --git a/packages/camera/camera_avfoundation/example/ios/Runner/AppDelegate.m b/packages/camera/camera_avfoundation/example/ios/Runner/AppDelegate.m deleted file mode 100644 index fff9545d5055..000000000000 --- a/packages/camera/camera_avfoundation/example/ios/Runner/AppDelegate.m +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright 2013 The Flutter Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "AppDelegate.h" -#include "GeneratedPluginRegistrant.h" - -@implementation AppDelegate - -- (BOOL)application:(UIApplication *)application - didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { - [GeneratedPluginRegistrant registerWithRegistry:self]; - // Override point for customization after application launch. - return [super application:application didFinishLaunchingWithOptions:launchOptions]; -} - -@end diff --git a/packages/camera/camera_avfoundation/example/ios/Runner/AppDelegate.swift b/packages/camera/camera_avfoundation/example/ios/Runner/AppDelegate.swift new file mode 100644 index 000000000000..ba78d5879052 --- /dev/null +++ b/packages/camera/camera_avfoundation/example/ios/Runner/AppDelegate.swift @@ -0,0 +1,27 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import Flutter +import UIKit + +@main +@objc class AppDelegate: FlutterAppDelegate, FlutterImplicitEngineDelegate { + override func application( + _ application: UIApplication, + didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? + ) -> Bool { + return super.application(application, didFinishLaunchingWithOptions: launchOptions) + } + + func didInitializeImplicitFlutterEngine(_ engineBridge: FlutterImplicitEngineBridge) { + // Plugin registration eventually sends camera operations on the background queue, which + // would run concurrently with the test cases during unit tests, making the debugging + // process confusing. This setup is actually not necessary for the unit tests, so + // skip it when running unit tests. + if NSClassFromString("XCTestCase") != nil { + return + } + GeneratedPluginRegistrant.register(with: engineBridge.pluginRegistry) + } +} diff --git a/packages/camera/camera_avfoundation/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/packages/camera/camera_avfoundation/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json index d225b3c2cfe2..d36b1fab2d9d 100644 --- a/packages/camera/camera_avfoundation/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json +++ b/packages/camera/camera_avfoundation/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -109,8 +109,9 @@ "scale" : "2x" }, { - "idiom" : "ios-marketing", "size" : "1024x1024", + "idiom" : "ios-marketing", + "filename" : "Icon-App-1024x1024@1x.png", "scale" : "1x" } ], @@ -118,4 +119,4 @@ "version" : 1, "author" : "xcode" } -} \ No newline at end of file +} diff --git a/packages/camera/camera_avfoundation/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png b/packages/camera/camera_avfoundation/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png new file mode 100644 index 000000000000..dc9ada4725e9 Binary files /dev/null and b/packages/camera/camera_avfoundation/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png differ diff --git a/packages/camera/camera_avfoundation/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png b/packages/camera/camera_avfoundation/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png index 28c6bf03016f..7353c41ecf9c 100644 Binary files a/packages/camera/camera_avfoundation/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png and b/packages/camera/camera_avfoundation/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png differ diff --git a/packages/camera/camera_avfoundation/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png b/packages/camera/camera_avfoundation/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png index 2ccbfd967d96..797d452e4589 100644 Binary files a/packages/camera/camera_avfoundation/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png and b/packages/camera/camera_avfoundation/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png differ diff --git a/packages/camera/camera_avfoundation/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/packages/camera/camera_avfoundation/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png index f091b6b0bca8..6ed2d933e112 100644 Binary files a/packages/camera/camera_avfoundation/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png and b/packages/camera/camera_avfoundation/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png differ diff --git a/packages/camera/camera_avfoundation/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png b/packages/camera/camera_avfoundation/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png index 4cde12118dda..4cd7b0099ca8 100644 Binary files a/packages/camera/camera_avfoundation/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png and b/packages/camera/camera_avfoundation/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png differ diff --git a/packages/camera/camera_avfoundation/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/packages/camera/camera_avfoundation/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png index d0ef06e7edb8..fe730945a01f 100644 Binary files a/packages/camera/camera_avfoundation/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png and b/packages/camera/camera_avfoundation/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png differ diff --git a/packages/camera/camera_avfoundation/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png b/packages/camera/camera_avfoundation/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png index dcdc2306c285..321773cd857a 100644 Binary files a/packages/camera/camera_avfoundation/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png and b/packages/camera/camera_avfoundation/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png differ diff --git a/packages/camera/camera_avfoundation/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png b/packages/camera/camera_avfoundation/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png index 2ccbfd967d96..797d452e4589 100644 Binary files a/packages/camera/camera_avfoundation/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png and b/packages/camera/camera_avfoundation/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png differ diff --git a/packages/camera/camera_avfoundation/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/packages/camera/camera_avfoundation/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png index c8f9ed8f5cee..502f463a9bc8 100644 Binary files a/packages/camera/camera_avfoundation/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png and b/packages/camera/camera_avfoundation/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png differ diff --git a/packages/camera/camera_avfoundation/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png b/packages/camera/camera_avfoundation/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png index a6d6b8609df0..0ec303439225 100644 Binary files a/packages/camera/camera_avfoundation/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png and b/packages/camera/camera_avfoundation/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png differ diff --git a/packages/camera/camera_avfoundation/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/packages/camera/camera_avfoundation/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png index a6d6b8609df0..0ec303439225 100644 Binary files a/packages/camera/camera_avfoundation/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png and b/packages/camera/camera_avfoundation/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png differ diff --git a/packages/camera/camera_avfoundation/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/packages/camera/camera_avfoundation/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png index 75b2d164a5a9..e9f5fea27c70 100644 Binary files a/packages/camera/camera_avfoundation/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png and b/packages/camera/camera_avfoundation/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png differ diff --git a/packages/camera/camera_avfoundation/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png b/packages/camera/camera_avfoundation/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png index c4df70d39da7..84ac32ae7d98 100644 Binary files a/packages/camera/camera_avfoundation/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png and b/packages/camera/camera_avfoundation/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png differ diff --git a/packages/camera/camera_avfoundation/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png b/packages/camera/camera_avfoundation/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png index 6a84f41e14e2..8953cba09064 100644 Binary files a/packages/camera/camera_avfoundation/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png and b/packages/camera/camera_avfoundation/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png differ diff --git a/packages/camera/camera_avfoundation/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png b/packages/camera/camera_avfoundation/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png index d0e1f5853602..0467bf12aa4d 100644 Binary files a/packages/camera/camera_avfoundation/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png and b/packages/camera/camera_avfoundation/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png differ diff --git a/packages/camera/camera_avfoundation/example/ios/Runner/Info.plist b/packages/camera/camera_avfoundation/example/ios/Runner/Info.plist index adb62fb7803d..90a69cb598b5 100644 --- a/packages/camera/camera_avfoundation/example/ios/Runner/Info.plist +++ b/packages/camera/camera_avfoundation/example/ios/Runner/Info.plist @@ -5,7 +5,9 @@ CADisableMinimumFrameDurationOnPhone CFBundleDevelopmentRegion - en + $(DEVELOPMENT_LANGUAGE) + CFBundleDisplayName + Camera Example CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier @@ -17,31 +19,47 @@ CFBundlePackageType APPL CFBundleShortVersionString - 1.0 + $(FLUTTER_BUILD_NAME) CFBundleSignature ???? CFBundleVersion - 1 - LSApplicationCategoryType - + $(FLUTTER_BUILD_NUMBER) LSRequiresIPhoneOS NSCameraUsageDescription Can I use the camera please? Only for demo purpose of the app NSMicrophoneUsageDescription Only for demo purpose of the app + UIApplicationSceneManifest + + UIApplicationSupportsMultipleScenes + + UISceneConfigurations + + UIWindowSceneSessionRoleApplication + + + UISceneClassName + UIWindowScene + UISceneConfigurationName + flutter + UISceneDelegateClassName + $(PRODUCT_MODULE_NAME).SceneDelegate + UISceneStoryboardFile + Main + + + + + UIApplicationSupportsIndirectInputEvents + UILaunchStoryboardName LaunchScreen UIMainStoryboardFile Main - UIRequiredDeviceCapabilities - - arm64 - UISupportedInterfaceOrientations UIInterfaceOrientationPortrait - UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight @@ -52,9 +70,5 @@ UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight - CADisableMinimumFrameDurationOnPhone - - UIApplicationSupportsIndirectInputEvents - diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/RunnerTests-Bridging-Header.h b/packages/camera/camera_avfoundation/example/ios/Runner/Runner-Bridging-Header.h similarity index 79% rename from packages/camera/camera_avfoundation/example/ios/RunnerTests/RunnerTests-Bridging-Header.h rename to packages/camera/camera_avfoundation/example/ios/Runner/Runner-Bridging-Header.h index 5b3a1852fb82..ba04211afd0a 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/RunnerTests-Bridging-Header.h +++ b/packages/camera/camera_avfoundation/example/ios/Runner/Runner-Bridging-Header.h @@ -2,4 +2,4 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#import "ExceptionCatcher.h" +#import "GeneratedPluginRegistrant.h" diff --git a/packages/webview_flutter/webview_flutter_wkwebview/example/ios/RunnerTests/RunnerTests-Bridging-Header.h b/packages/camera/camera_avfoundation/example/ios/Runner/SceneDelegate.swift similarity index 65% rename from packages/webview_flutter/webview_flutter_wkwebview/example/ios/RunnerTests/RunnerTests-Bridging-Header.h rename to packages/camera/camera_avfoundation/example/ios/Runner/SceneDelegate.swift index c14bff0c31d9..8c7b10c639d1 100644 --- a/packages/webview_flutter/webview_flutter_wkwebview/example/ios/RunnerTests/RunnerTests-Bridging-Header.h +++ b/packages/camera/camera_avfoundation/example/ios/Runner/SceneDelegate.swift @@ -2,4 +2,9 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#import "TemporaryObjCStub.h" +import Flutter +import UIKit + +class SceneDelegate: FlutterSceneDelegate { + +} diff --git a/packages/camera/camera_avfoundation/example/ios/Runner/main.m b/packages/camera/camera_avfoundation/example/ios/Runner/main.m deleted file mode 100644 index 3ec494eae7e8..000000000000 --- a/packages/camera/camera_avfoundation/example/ios/Runner/main.m +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright 2013 The Flutter Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#import -#import -#import "AppDelegate.h" - -int main(int argc, char *argv[]) { - @autoreleasepool { - // The setup logic in `AppDelegate::didFinishLaunchingWithOptions:` eventually sends camera - // operations on the background queue, which would run concurrently with the test cases during - // unit tests, making the debugging process confusing. This setup is actually not necessary for - // the unit tests, so it is better to skip the AppDelegate when running unit tests. - BOOL isTesting = NSClassFromString(@"XCTestCase") != nil; - return UIApplicationMain(argc, argv, nil, - isTesting ? nil : NSStringFromClass([AppDelegate class])); - } -} diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/FLTCamExposureTests.swift b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraExposureTests.swift similarity index 99% rename from packages/camera/camera_avfoundation/example/ios/RunnerTests/FLTCamExposureTests.swift rename to packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraExposureTests.swift index 33ee0325b8e0..da5531b652bb 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/FLTCamExposureTests.swift +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraExposureTests.swift @@ -6,7 +6,7 @@ import XCTest @testable import camera_avfoundation -final class FLTCamExposureTests: XCTestCase { +final class CameraExposureTests: XCTestCase { private func createCamera() -> (Camera, MockCaptureDevice, MockDeviceOrientationProvider) { let mockDevice = MockCaptureDevice() let mockDeviceOrientationProvider = MockDeviceOrientationProvider() diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraPluginCreateCameraTests.swift b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraPluginCreateCameraTests.swift index 5eb2b61e8ea2..269ba03067b0 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraPluginCreateCameraTests.swift +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraPluginCreateCameraTests.swift @@ -98,7 +98,7 @@ final class CameraPluginCreateCameraTests: XCTestCase { XCTAssertTrue(requestAudioPermissionCalled) } - func testCreateCamera_createsFLTCamSuccessfully() { + func testCreateCamera_createsCameraSuccessfully() { let (cameraPlugin, mockPermissionManager, mockCaptureSession) = createCameraPlugin() let expectation = expectation(description: "Initialization completed") diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraPluginDelegatingMethodTests.swift b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraPluginDelegatingMethodTests.swift index 4e3c5a377f06..34a306b511d7 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraPluginDelegatingMethodTests.swift +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraPluginDelegatingMethodTests.swift @@ -6,7 +6,7 @@ import XCTest @testable import camera_avfoundation -/// Tests of `CameraPlugin` methods delegating to `FLTCam` instance +/// Tests of `CameraPlugin` methods delegating to `Camera` instance final class CameraPluginDelegatingMethodTests: XCTestCase { private func createCameraPlugin() -> (CameraPlugin, MockCamera) { let mockCamera = MockCamera() diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraSessionPresetsTests.swift b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraSessionPresetsTests.swift index b7b6a00734be..5d56567959f0 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraSessionPresetsTests.swift +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraSessionPresetsTests.swift @@ -7,7 +7,7 @@ import XCTest @testable import camera_avfoundation -/// Includes test cases related to resolution presets setting operations for FLTCam class. +/// Includes test cases related to resolution presets setting operations for Camera class. final class CameraSessionPresetsTests: XCTestCase { func testResolutionPresetWithBestFormat_mustUpdateCaptureSessionPreset() { let expectedPreset = AVCaptureSession.Preset.inputPriority diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/FLTCamSetDeviceOrientationTests.swift b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraSetDeviceOrientationTests.swift similarity index 98% rename from packages/camera/camera_avfoundation/example/ios/RunnerTests/FLTCamSetDeviceOrientationTests.swift rename to packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraSetDeviceOrientationTests.swift index ab688c9f5933..c6ca992d236b 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/FLTCamSetDeviceOrientationTests.swift +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraSetDeviceOrientationTests.swift @@ -7,7 +7,7 @@ import XCTest @testable import camera_avfoundation -final class FLTCamSetDeviceOrientationTests: XCTestCase { +final class CameraSetDeviceOrientationTests: XCTestCase { private func createCamera() -> (Camera, MockCaptureConnection, MockCaptureConnection) { let camera = CameraTestUtils.createTestCamera() diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/FLTCamSetFlashModeTests.swift b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraSetFlashModeTests.swift similarity index 98% rename from packages/camera/camera_avfoundation/example/ios/RunnerTests/FLTCamSetFlashModeTests.swift rename to packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraSetFlashModeTests.swift index 0941a06d96e4..7a931a7f1e25 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/FLTCamSetFlashModeTests.swift +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraSetFlashModeTests.swift @@ -7,7 +7,7 @@ import XCTest @testable import camera_avfoundation -final class FLTCamSetFlashModeTests: XCTestCase { +final class CameraSetFlashModeTests: XCTestCase { private func createCamera() -> (Camera, MockCaptureDevice, MockCapturePhotoOutput) { let mockDevice = MockCaptureDevice() let mockCapturePhotoOutput = MockCapturePhotoOutput() diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/FLTCamFocusTests.swift b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraSetFocusModeTests.swift similarity index 99% rename from packages/camera/camera_avfoundation/example/ios/RunnerTests/FLTCamFocusTests.swift rename to packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraSetFocusModeTests.swift index 00eaddf71faf..75c1cf38e6fb 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/FLTCamFocusTests.swift +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraSetFocusModeTests.swift @@ -7,7 +7,7 @@ import XCTest @testable import camera_avfoundation -final class FLTCamSetFocusModeTests: XCTestCase { +final class CameraSetFocusModeTests: XCTestCase { private func createCamera() -> (Camera, MockCaptureDevice, MockDeviceOrientationProvider) { let mockDevice = MockCaptureDevice() let mockDeviceOrientationProvider = MockDeviceOrientationProvider() diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraSettingsTests.swift b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraSettingsTests.swift index 984549b06516..0c9f45e5e50a 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraSettingsTests.swift +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraSettingsTests.swift @@ -3,6 +3,7 @@ // found in the LICENSE file. import AVFoundation +import Flutter import XCTest @testable import camera_avfoundation @@ -51,7 +52,7 @@ private final class TestMediaSettingsAVWrapper: FLTCamMediaSettingsAVWrapper { } override func setMinFrameDuration(_ duration: CMTime, on captureDevice: CaptureDevice) { - // FLTCam allows to set frame rate with 1/10 precision. + // Camera allows to set frame rate with 1/10 precision. let expectedDuration = CMTimeMake(value: 10, timescale: Int32(testFramesPerSecond * 10)) if duration == expectedDuration { minFrameDurationExpectation.fulfill() @@ -59,7 +60,7 @@ private final class TestMediaSettingsAVWrapper: FLTCamMediaSettingsAVWrapper { } override func setMaxFrameDuration(_ duration: CMTime, on captureDevice: CaptureDevice) { - // FLTCam allows to set frame rate with 1/10 precision. + // Camera allows to set frame rate with 1/10 precision. let expectedDuration = CMTimeMake(value: 10, timescale: Int32(testFramesPerSecond * 10)) if duration == expectedDuration { maxFrameDurationExpectation.fulfill() diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/FLTCamZoomTests.swift b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraZoomTests.swift similarity index 98% rename from packages/camera/camera_avfoundation/example/ios/RunnerTests/FLTCamZoomTests.swift rename to packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraZoomTests.swift index 46f302058b06..f0c62add69fb 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/FLTCamZoomTests.swift +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraZoomTests.swift @@ -7,7 +7,7 @@ import XCTest @testable import camera_avfoundation -final class FLTCamZoomTests: XCTestCase { +final class CameraZoomTests: XCTestCase { private func createCamera() -> (Camera, MockCaptureDevice) { let mockDevice = MockCaptureDevice() diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/ExceptionCatcher.h b/packages/camera/camera_avfoundation/example/ios/RunnerTests/ExceptionCatcher.h deleted file mode 100644 index 4c7ae95dac32..000000000000 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/ExceptionCatcher.h +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2013 The Flutter Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// TODO(FirentisTFW): Remove this file when the plugin code that uses it is migrated to Swift. -// After the migration, the code should throw Swift errors instead of Objective-C exceptions, thus -// this file will not be needed. - -#import - -NS_ASSUME_NONNULL_BEGIN - -/// A utility class for catching Objective-C exceptions. -/// -/// It allows to execute a block of code and catch any exceptions that are thrown during its -/// execution. This is useful for bridging between Objective-C and Swift code, as Swift does not -/// support catching Objective-C exceptions directly. -@interface ExceptionCatcher : NSObject -/// Executes a block of code and catches any exceptions that are thrown. -+ (nullable NSException *)catchException:(void (^)(void))tryBlock; -@end - -NS_ASSUME_NONNULL_END diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/ExceptionCatcher.m b/packages/camera/camera_avfoundation/example/ios/RunnerTests/ExceptionCatcher.m deleted file mode 100644 index febd9ac4f79d..000000000000 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/ExceptionCatcher.m +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright 2013 The Flutter Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#import "ExceptionCatcher.h" - -@implementation ExceptionCatcher -+ (nullable NSException *)catchException:(void (^)(void))tryBlock { - @try { - tryBlock(); - // No exception occurred. - return nil; - } @catch (NSException *exception) { - return exception; - } -} -@end diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Info.plist b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Info.plist deleted file mode 100644 index 64d65ca49577..000000000000 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Info.plist +++ /dev/null @@ -1,22 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - $(PRODUCT_BUNDLE_PACKAGE_TYPE) - CFBundleShortVersionString - 1.0 - CFBundleVersion - 1 - - diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCameraDeviceDiscoverer.swift b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCameraDeviceDiscoverer.swift index 972f34ab8d5e..f621aa620b5c 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCameraDeviceDiscoverer.swift +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCameraDeviceDiscoverer.swift @@ -6,7 +6,7 @@ import AVFoundation @testable import camera_avfoundation -/// Mock implementation of `FLTCameraDeviceDiscoverer` protocol which allows injecting a custom +/// Mock implementation of `CameraDeviceDiscoverer` protocol which allows injecting a custom /// implementation for session discovery. final class MockCameraDeviceDiscoverer: NSObject, CameraDeviceDiscoverer { var discoverySessionStub: diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureDevice.swift b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureDevice.swift index be6fc7dca28a..71fe2fc8f7da 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureDevice.swift +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureDevice.swift @@ -6,7 +6,7 @@ import AVFoundation @testable import camera_avfoundation -/// A mock implementation of `FLTCaptureDevice` that allows mocking the class +/// A mock implementation of `CaptureDevice` that allows mocking the class /// properties. class MockCaptureDevice: NSObject, CaptureDevice { var activeFormatStub: (() -> CaptureDeviceFormat)? diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureDeviceInputFactory.swift b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureDeviceInputFactory.swift index 9292b6256d7c..0222750a43e1 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureDeviceInputFactory.swift +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureDeviceInputFactory.swift @@ -2,9 +2,11 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +import Foundation + @testable import camera_avfoundation -///// A mocked implementation of FLTCaptureDeviceInputFactory which allows injecting a custom +///// A mocked implementation of CaptureDeviceInputFactory which allows injecting a custom ///// implementation. final class MockCaptureDeviceInputFactory: NSObject, CaptureDeviceInputFactory { func deviceInput(with device: CaptureDevice) throws -> CaptureInput { diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureInput.swift b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureInput.swift index 74d8742bd161..394dbf9b5b67 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureInput.swift +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureInput.swift @@ -6,7 +6,7 @@ import AVFoundation @testable import camera_avfoundation -/// A mocked implementation of FLTCaptureInput which allows injecting a custom +/// A mocked implementation of CaptureInput which allows injecting a custom /// implementation. final class MockCaptureInput: NSObject, CaptureInput { var avInput: AVCaptureInput { diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCapturePhotoOutput.swift b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCapturePhotoOutput.swift index a0b2faee8c00..184fd0be36b2 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCapturePhotoOutput.swift +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCapturePhotoOutput.swift @@ -6,7 +6,7 @@ import AVFoundation @testable import camera_avfoundation -/// Mock implementation of `FLTCapturePhotoOutput` protocol which allows injecting a custom +/// Mock implementation of `CapturePhotoOutput` protocol which allows injecting a custom /// implementation. final class MockCapturePhotoOutput: NSObject, CapturePhotoOutput { var avOutput = AVCapturePhotoOutput() diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureSession.swift b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureSession.swift index 08d2427b4438..23ce72bbe9f8 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureSession.swift +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureSession.swift @@ -6,7 +6,7 @@ import AVFoundation @testable import camera_avfoundation -/// Mock implementation of `FLTCaptureSession` protocol which allows injecting a custom +/// Mock implementation of `CaptureSession` protocol which allows injecting a custom /// implementation. final class MockCaptureSession: NSObject, CaptureSession { var setSessionPresetStub: ((AVCaptureSession.Preset) -> Void)? diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureVideoDataOutput.swift b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureVideoDataOutput.swift index c36397321201..23e54734f853 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureVideoDataOutput.swift +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureVideoDataOutput.swift @@ -6,7 +6,7 @@ import AVFoundation @testable import camera_avfoundation -/// Mock implementation of `FLTCaptureVideoDataOutput` protocol which allows injecting a custom +/// Mock implementation of `CaptureVideoDataOutput` protocol which allows injecting a custom /// implementation. class MockCaptureVideoDataOutput: NSObject, CaptureVideoDataOutput { var avOutput = AVCaptureVideoDataOutput() diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockFrameRateRange.swift b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockFrameRateRange.swift index 1130a35937e7..d4bfbda30385 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockFrameRateRange.swift +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockFrameRateRange.swift @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +import Foundation + @testable import camera_avfoundation /// A mock implementation of `FrameRateRange` that allows mocking the class properties. diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockWritableData.swift b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockWritableData.swift index 9feb13e3f997..8666c4d96093 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockWritableData.swift +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockWritableData.swift @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +import Foundation + @testable import camera_avfoundation /// A mock implementation of `WritableData` that allows injecting a custom implementation diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/PhotoCaptureTests.swift b/packages/camera/camera_avfoundation/example/ios/RunnerTests/PhotoCaptureTests.swift index e20a15dba9d3..1113fb424450 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/PhotoCaptureTests.swift +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/PhotoCaptureTests.swift @@ -7,7 +7,7 @@ import XCTest @testable import camera_avfoundation -/// Includes test cases related to photo capture operations for FLTCam class. +/// Includes test cases related to photo capture operations for Camera class. final class PhotoCaptureTests: XCTestCase { private func createCam(with captureSessionQueue: DispatchQueue) -> DefaultCamera { let configuration = CameraTestUtils.createTestCameraConfiguration() @@ -36,7 +36,7 @@ final class PhotoCaptureTests: XCTestCase { } cam.capturePhotoOutput = mockOutput - // `FLTCam::captureToFile` runs on capture session queue. + // `Camera.captureToFile` runs on capture session queue. captureSessionQueue.async { cam.captureToFile { result in switch result { @@ -73,7 +73,7 @@ final class PhotoCaptureTests: XCTestCase { } cam.capturePhotoOutput = mockOutput - // `FLTCam::captureToFile` runs on capture session queue. + // `Camera.captureToFile` runs on capture session queue. captureSessionQueue.async { cam.captureToFile { result in switch result { @@ -112,7 +112,7 @@ final class PhotoCaptureTests: XCTestCase { } cam.capturePhotoOutput = mockOutput - // `FLTCam::captureToFile` runs on capture session queue. + // `Camera.captureToFile` runs on capture session queue. captureSessionQueue.async { cam.captureToFile { result in if let filePath = self.assertSuccess(result) { @@ -148,7 +148,7 @@ final class PhotoCaptureTests: XCTestCase { } cam.capturePhotoOutput = mockOutput - // `FLTCam::captureToFile` runs on capture session queue. + // `Camera.captureToFile` runs on capture session queue. captureSessionQueue.async { cam.captureToFile { result in if let filePath = self.assertSuccess(result) { @@ -198,7 +198,7 @@ final class PhotoCaptureTests: XCTestCase { } cam.capturePhotoOutput = mockOutput - // `FLTCam::captureToFile` runs on capture session queue. + // `Camera.captureToFile` runs on capture session queue. captureSessionQueue.async { cam.setFlashMode(.torch) { _ in } cam.captureToFile { result in diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/SampleBufferTests.swift b/packages/camera/camera_avfoundation/example/ios/RunnerTests/SampleBufferTests.swift index 3db6cd2c94da..98759f16caba 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/SampleBufferTests.swift +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/SampleBufferTests.swift @@ -61,7 +61,7 @@ private class FakeMediaSettingsAVWrapper: FLTCamMediaSettingsAVWrapper { } } -/// Includes test cases related to sample buffer handling for FLTCam class. +/// Includes test cases related to sample buffer handling for Camera class. final class CameraSampleBufferTests: XCTestCase { private func createCamera() -> ( DefaultCamera, @@ -119,7 +119,7 @@ final class CameraSampleBufferTests: XCTestCase { let deliveredPixelBuffer = camera.copyPixelBuffer()?.takeRetainedValue() XCTAssertEqual( deliveredPixelBuffer, capturedPixelBuffer, - "FLTCam must deliver the latest captured pixel buffer to copyPixelBuffer API.") + "Camera must deliver the latest captured pixel buffer to copyPixelBuffer API.") } func testDidOutputSampleBuffer_mustNotChangeSampleBufferRetainCountAfterPauseResumeRecording() { diff --git a/packages/camera/camera_avfoundation/example/lib/camera_controller.dart b/packages/camera/camera_avfoundation/example/lib/camera_controller.dart index 84850b8d928f..ed3a8e5a953d 100644 --- a/packages/camera/camera_avfoundation/example/lib/camera_controller.dart +++ b/packages/camera/camera_avfoundation/example/lib/camera_controller.dart @@ -502,13 +502,7 @@ class Optional extends IterableBase { const Optional.absent() : _value = null; /// Constructs an Optional of the given [value]. - /// - /// Throws [ArgumentError] if [value] is null. - Optional.of(T value) : _value = value { - // TODO(cbracken): Delete and make this ctor const once mixed-mode - // execution is no longer around. - ArgumentError.checkNotNull(value); - } + const Optional.of(T value) : _value = value; /// Constructs an Optional of the given [value]. /// diff --git a/packages/camera/camera_web/example/integration_test/helpers/mocks.dart b/packages/camera/camera_web/example/integration_test/helpers/mocks.dart index aafdcc0895ac..fa5c35214e9b 100644 --- a/packages/camera/camera_web/example/integration_test/helpers/mocks.dart +++ b/packages/camera/camera_web/example/integration_test/helpers/mocks.dart @@ -8,15 +8,12 @@ import 'dart:async'; import 'dart:js_interop'; import 'dart:ui'; -// ignore_for_file: implementation_imports import 'package:camera_web/src/camera.dart'; import 'package:camera_web/src/camera_service.dart'; import 'package:camera_web/src/shims/dart_js_util.dart'; import 'package:camera_web/src/types/types.dart'; import 'package:mockito/annotations.dart'; import 'package:mockito/mockito.dart'; -// TODO(srujzs): This is exported in `package:web` 0.6.0. Remove this when it is available. -import 'package:web/src/helpers/events/streams.dart'; import 'package:web/web.dart' as web; @GenerateNiceMocks(>[ @@ -80,12 +77,12 @@ class MockScreen { @JSExport() class MockScreenOrientation { - /// JSPromise Function(web.OrientationLockType orientation) + /// `JSPromise Function(web.OrientationLockType orientation)` JSFunction lock = (web.OrientationLockType orientation) { return Future.value().toJS; }.toJS; - /// void Function() + /// `void Function()` late JSFunction unlock; late web.OrientationType type; } @@ -97,7 +94,7 @@ class MockDocument { @JSExport() class MockElement { - /// JSPromise Function([FullscreenOptions options]) + /// `JSPromise Function([FullscreenOptions options])` JSFunction requestFullscreen = ([web.FullscreenOptions? options]) { return Future.value().toJS; }.toJS; @@ -110,30 +107,30 @@ class MockNavigator { @JSExport() class MockMediaDevices { - /// JSPromise Function([web.MediaStreamConstraints? constraints]) + /// `JSPromise Function([web.MediaStreamConstraints? constraints])` late JSFunction getUserMedia; - /// web.MediaTrackSupportedConstraints Function() + /// `web.MediaTrackSupportedConstraints Function()` late JSFunction getSupportedConstraints; - /// JSPromise> Function() + /// `JSPromise> Function()` late JSFunction enumerateDevices; } @JSExport() class MockMediaStreamTrack { - /// web.MediaTrackCapabilities Function(); + /// `web.MediaTrackCapabilities Function()` late JSFunction getCapabilities; - /// web.MediaTrackSettings Function() + /// `web.MediaTrackSettings Function()` JSFunction getSettings = () { return web.MediaTrackSettings(); }.toJS; - /// JSPromise Function([web.MediaTrackConstraints? constraints]) + /// `JSPromise Function([web.MediaTrackConstraints? constraints])` late JSFunction applyConstraints; - /// void Function() + /// `void Function()` JSFunction stop = () {}.toJS; } @@ -145,24 +142,24 @@ class MockVideoElement { @JSExport() class MockMediaRecorder { - /// void Function(String type, web.EventListener? callback, [JSAny options]) + /// `void Function(String type, web.EventListener? callback, [JSAny options])` JSFunction addEventListener = (String type, web.EventListener? callback, [JSAny? options]) {}.toJS; - /// void Function(String type, web.EventListener? callback, [JSAny options]) + /// `void Function(String type, web.EventListener? callback, [JSAny options])` JSFunction removeEventListener = (String type, web.EventListener? callback, [JSAny? options]) {}.toJS; - /// void Function([int timeslice]) + /// `void Function([int timeslice])` JSFunction start = ([int? timeslice]) {}.toJS; - /// void Function() + /// `void Function()` JSFunction pause = () {}.toJS; - /// void Function() + /// `void Function()` JSFunction resume = () {}.toJS; - /// void Function() + /// `void Function()` JSFunction stop = () {}.toJS; web.RecordingState state = 'inactive'; @@ -197,9 +194,9 @@ class FakeMediaError { final String message; } -/// A fake [ElementStream] that listens to the provided [_stream] on [listen]. +/// A fake [web.ElementStream] that listens to the provided [_stream] on [listen]. class FakeElementStream extends Fake - implements ElementStream { + implements web.ElementStream { FakeElementStream(this._stream); final Stream _stream; @@ -220,7 +217,7 @@ class FakeElementStream extends Fake } } -/// A fake [BlobEvent] that returns the provided blob [data]. +/// A fake [web.BlobEvent] that returns the provided blob [data]. @JSExport() class FakeBlobEvent { FakeBlobEvent(this.data); @@ -228,7 +225,7 @@ class FakeBlobEvent { final web.Blob? data; } -/// A fake [DomException] that returns the provided error [_name] and [_message]. +/// A fake [web.DomException] that returns the provided error [_name] and [_message]. @JSExport() class FakeErrorEvent { FakeErrorEvent(this.type, [this.message = '']); @@ -272,7 +269,7 @@ class MockEventStreamProvider extends Mock } @override - ElementStream forElement(web.Element? e, {bool? useCapture = false}) { + web.ElementStream forElement(web.Element? e, {bool? useCapture = false}) { return super.noSuchMethod( Invocation.method( #forElement, @@ -281,7 +278,7 @@ class MockEventStreamProvider extends Mock ), returnValue: FakeElementStream(Stream.empty()), ) - as ElementStream; + as web.ElementStream; } } diff --git a/packages/espresso/CHANGELOG.md b/packages/espresso/CHANGELOG.md index e944f4264b9e..a48867160766 100644 --- a/packages/espresso/CHANGELOG.md +++ b/packages/espresso/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.4.0+24 + +* Updates build files from Groovy to Kotlin. + ## 0.4.0+23 * Removed the unused `io.flutter.network-policy` metadata tag from the README and example application. diff --git a/packages/espresso/android/build.gradle b/packages/espresso/android/build.gradle.kts similarity index 80% rename from packages/espresso/android/build.gradle rename to packages/espresso/android/build.gradle.kts index cadf4a2c1cf5..db131e30cfdd 100644 --- a/packages/espresso/android/build.gradle +++ b/packages/espresso/android/build.gradle.kts @@ -12,14 +12,16 @@ buildscript { } } -rootProject.allprojects { +allprojects { repositories { google() mavenCentral() } } -apply plugin: 'com.android.library' +plugins { + id("com.android.library") +} android { namespace = "com.example.espresso" @@ -38,19 +40,20 @@ android { lint { checkAllWarnings = true warningsAsErrors = true - disable 'AndroidGradlePluginVersion', 'InvalidPackage', 'GradleDependency', 'NewerVersionAvailable' + disable.addAll(setOf("AndroidGradlePluginVersion", "InvalidPackage", "GradleDependency", "NewerVersionAvailable")) baseline = file("lint-baseline.xml") } - testOptions { - unitTests.includeAndroidResources = true - unitTests.returnDefaultValues = true - unitTests.all { - testLogging { - events "passed", "skipped", "failed", "standardOut", "standardError" - outputs.upToDateWhen {false} - showStandardStreams = true + unitTests { + isIncludeAndroidResources = true + isReturnDefaultValues = true + all { + it.outputs.upToDateWhen { false } + it.testLogging { + events("passed", "skipped", "failed", "standardOut", "standardError") + showStandardStreams = true + } } } } diff --git a/packages/espresso/android/settings.gradle b/packages/espresso/android/settings.gradle deleted file mode 100644 index 46643c1c5e02..000000000000 --- a/packages/espresso/android/settings.gradle +++ /dev/null @@ -1 +0,0 @@ -rootProject.name = 'espresso' diff --git a/packages/espresso/android/settings.gradle.kts b/packages/espresso/android/settings.gradle.kts new file mode 100644 index 000000000000..ecf97c03a52c --- /dev/null +++ b/packages/espresso/android/settings.gradle.kts @@ -0,0 +1 @@ +rootProject.name = "espresso" diff --git a/packages/espresso/pubspec.yaml b/packages/espresso/pubspec.yaml index 63e77af8c5a9..785f52f716f6 100644 --- a/packages/espresso/pubspec.yaml +++ b/packages/espresso/pubspec.yaml @@ -3,7 +3,7 @@ description: Java classes for testing Flutter apps using Espresso. Allows driving Flutter widgets from a native Espresso test. repository: https://github.com/flutter/packages/tree/main/packages/espresso issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+espresso%22 -version: 0.4.0+23 +version: 0.4.0+24 environment: sdk: ^3.9.0 diff --git a/packages/file_selector/file_selector_android/CHANGELOG.md b/packages/file_selector/file_selector_android/CHANGELOG.md index 7e0e36773d2d..070599f8e5d7 100644 --- a/packages/file_selector/file_selector_android/CHANGELOG.md +++ b/packages/file_selector/file_selector_android/CHANGELOG.md @@ -1,5 +1,6 @@ -## NEXT +## 0.5.2+5 +* Updates build files from Groovy to Kotlin. * Updates minimum supported SDK version to Flutter 3.35/Dart 3.9. ## 0.5.2+4 diff --git a/packages/file_selector/file_selector_android/android/build.gradle b/packages/file_selector/file_selector_android/android/build.gradle.kts similarity index 66% rename from packages/file_selector/file_selector_android/android/build.gradle rename to packages/file_selector/file_selector_android/android/build.gradle.kts index 99f31fe552b9..7a9ace9f9f05 100644 --- a/packages/file_selector/file_selector_android/android/build.gradle +++ b/packages/file_selector/file_selector_android/android/build.gradle.kts @@ -12,14 +12,16 @@ buildscript { } } -rootProject.allprojects { +allprojects { repositories { google() mavenCentral() } } -apply plugin: 'com.android.library' +plugins { + id("com.android.library") +} android { namespace = "dev.flutter.packages.file_selector_android" @@ -45,17 +47,19 @@ android { lint { checkAllWarnings = true warningsAsErrors = true - disable 'AndroidGradlePluginVersion', 'InvalidPackage', 'GradleDependency', 'NewerVersionAvailable' + disable.addAll(setOf("AndroidGradlePluginVersion", "InvalidPackage", "GradleDependency", "NewerVersionAvailable")) } testOptions { - unitTests.includeAndroidResources = true - unitTests.returnDefaultValues = true - unitTests.all { - testLogging { - events "passed", "skipped", "failed", "standardOut", "standardError" - outputs.upToDateWhen {false} - showStandardStreams = true + unitTests { + isIncludeAndroidResources = true + isReturnDefaultValues = true + all { + it.outputs.upToDateWhen { false } + it.testLogging { + events("passed", "skipped", "failed", "standardOut", "standardError") + showStandardStreams = true + } } } } diff --git a/packages/file_selector/file_selector_android/android/settings.gradle b/packages/file_selector/file_selector_android/android/settings.gradle deleted file mode 100644 index 679b28be66a4..000000000000 --- a/packages/file_selector/file_selector_android/android/settings.gradle +++ /dev/null @@ -1 +0,0 @@ -rootProject.name = 'file_selector_android' diff --git a/packages/file_selector/file_selector_android/android/settings.gradle.kts b/packages/file_selector/file_selector_android/android/settings.gradle.kts new file mode 100644 index 000000000000..49fb054f3458 --- /dev/null +++ b/packages/file_selector/file_selector_android/android/settings.gradle.kts @@ -0,0 +1 @@ +rootProject.name = "file_selector_android" diff --git a/packages/file_selector/file_selector_android/pubspec.yaml b/packages/file_selector/file_selector_android/pubspec.yaml index 042236bfae85..80440caaa287 100644 --- a/packages/file_selector/file_selector_android/pubspec.yaml +++ b/packages/file_selector/file_selector_android/pubspec.yaml @@ -2,7 +2,7 @@ name: file_selector_android description: Android implementation of the file_selector package. repository: https://github.com/flutter/packages/tree/main/packages/file_selector/file_selector_android issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+file_selector%22 -version: 0.5.2+4 +version: 0.5.2+5 environment: sdk: ^3.9.0 diff --git a/packages/flutter_plugin_android_lifecycle/CHANGELOG.md b/packages/flutter_plugin_android_lifecycle/CHANGELOG.md index 85dd8c13e2e1..aec558de4c34 100644 --- a/packages/flutter_plugin_android_lifecycle/CHANGELOG.md +++ b/packages/flutter_plugin_android_lifecycle/CHANGELOG.md @@ -1,5 +1,6 @@ -## NEXT +## 2.0.34 +* Updates build files from Groovy to Kotlin. * Updates README to reflect currently supported OS version. ## 2.0.33 diff --git a/packages/flutter_plugin_android_lifecycle/android/build.gradle b/packages/flutter_plugin_android_lifecycle/android/build.gradle.kts similarity index 66% rename from packages/flutter_plugin_android_lifecycle/android/build.gradle rename to packages/flutter_plugin_android_lifecycle/android/build.gradle.kts index 3e48512de64a..e8cd82a5de60 100644 --- a/packages/flutter_plugin_android_lifecycle/android/build.gradle +++ b/packages/flutter_plugin_android_lifecycle/android/build.gradle.kts @@ -12,14 +12,16 @@ buildscript { } } -rootProject.allprojects { +allprojects { repositories { google() mavenCentral() } } -apply plugin: 'com.android.library' +plugins { + id("com.android.library") +} android { namespace = "io.flutter.plugins.flutter_plugin_android_lifecycle" @@ -39,22 +41,23 @@ android { lint { checkAllWarnings = true warningsAsErrors = true - disable 'AndroidGradlePluginVersion', 'InvalidPackage', 'GradleDependency', 'NewerVersionAvailable' + disable.addAll(setOf("AndroidGradlePluginVersion", "InvalidPackage", "GradleDependency", "NewerVersionAvailable")) } dependencies { implementation("androidx.annotation:annotation:1.9.1") } - testOptions { - unitTests.includeAndroidResources = true - unitTests.returnDefaultValues = true - unitTests.all { - testLogging { - events "passed", "skipped", "failed", "standardOut", "standardError" - outputs.upToDateWhen {false} - showStandardStreams = true + unitTests { + isIncludeAndroidResources = true + isReturnDefaultValues = true + all { + it.outputs.upToDateWhen { false } + it.testLogging { + events("passed", "skipped", "failed", "standardOut", "standardError") + showStandardStreams = true + } } } } diff --git a/packages/flutter_plugin_android_lifecycle/android/settings.gradle b/packages/flutter_plugin_android_lifecycle/android/settings.gradle deleted file mode 100644 index 70836e6e7200..000000000000 --- a/packages/flutter_plugin_android_lifecycle/android/settings.gradle +++ /dev/null @@ -1 +0,0 @@ -rootProject.name = 'flutter_plugin_android_lifecycle' diff --git a/packages/flutter_plugin_android_lifecycle/android/settings.gradle.kts b/packages/flutter_plugin_android_lifecycle/android/settings.gradle.kts new file mode 100644 index 000000000000..5c21302de099 --- /dev/null +++ b/packages/flutter_plugin_android_lifecycle/android/settings.gradle.kts @@ -0,0 +1 @@ +rootProject.name = "flutter_plugin_android_lifecycle" diff --git a/packages/flutter_plugin_android_lifecycle/pubspec.yaml b/packages/flutter_plugin_android_lifecycle/pubspec.yaml index 6c146b98342e..038fc39804aa 100644 --- a/packages/flutter_plugin_android_lifecycle/pubspec.yaml +++ b/packages/flutter_plugin_android_lifecycle/pubspec.yaml @@ -2,7 +2,7 @@ name: flutter_plugin_android_lifecycle description: Flutter plugin for accessing an Android Lifecycle within other plugins. repository: https://github.com/flutter/packages/tree/main/packages/flutter_plugin_android_lifecycle issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+flutter_plugin_android_lifecycle%22 -version: 2.0.33 +version: 2.0.34 environment: sdk: ^3.9.0 diff --git a/packages/go_router_builder/CHANGELOG.md b/packages/go_router_builder/CHANGELOG.md index f9e9da0393ab..498ba7174dcb 100644 --- a/packages/go_router_builder/CHANGELOG.md +++ b/packages/go_router_builder/CHANGELOG.md @@ -1,3 +1,7 @@ +## 4.2.1 + +* Adds support for analyzer 11 and 12. + ## 4.2.0 - Adds supports for `TypedQueryParameter` annotation. diff --git a/packages/go_router_builder/pubspec.yaml b/packages/go_router_builder/pubspec.yaml index 9985c37166a4..536b9c94b813 100644 --- a/packages/go_router_builder/pubspec.yaml +++ b/packages/go_router_builder/pubspec.yaml @@ -2,7 +2,7 @@ name: go_router_builder description: >- A builder that supports generated strongly-typed route helpers for package:go_router -version: 4.2.0 +version: 4.2.1 repository: https://github.com/flutter/packages/tree/main/packages/go_router_builder issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+go_router_builder%22 @@ -11,7 +11,7 @@ environment: flutter: ">=3.35.0" dependencies: - analyzer: ">=8.2.0 <10.0.0" + analyzer: ">=8.2.0 <13.0.0" async: ^2.8.0 # TODO(piinks): Pin version once new stable rolls. build: ">=3.0.0 <5.0.0" diff --git a/packages/google_maps_flutter/google_maps_flutter_android/CHANGELOG.md b/packages/google_maps_flutter/google_maps_flutter_android/CHANGELOG.md index 51d54ce382e3..d19b5b24f8c0 100644 --- a/packages/google_maps_flutter/google_maps_flutter_android/CHANGELOG.md +++ b/packages/google_maps_flutter/google_maps_flutter_android/CHANGELOG.md @@ -1,3 +1,11 @@ +## 2.19.5 + +* Fixes a crash when using the legacy map renderer by adding the `org.apache.http.legacy` library. + +## 2.19.4 + +* Updates build files from Groovy to Kotlin. + ## 2.19.3 * Batches clustered marker add/remove operations to avoid redundant re-rendering. diff --git a/packages/google_maps_flutter/google_maps_flutter_android/android/build.gradle b/packages/google_maps_flutter/google_maps_flutter_android/android/build.gradle.kts similarity index 61% rename from packages/google_maps_flutter/google_maps_flutter_android/android/build.gradle rename to packages/google_maps_flutter/google_maps_flutter_android/android/build.gradle.kts index d65271558ea7..61cdabfbbf01 100644 --- a/packages/google_maps_flutter/google_maps_flutter_android/android/build.gradle +++ b/packages/google_maps_flutter/google_maps_flutter_android/android/build.gradle.kts @@ -12,14 +12,16 @@ buildscript { } } -rootProject.allprojects { +allprojects { repositories { google() mavenCentral() } } -apply plugin: 'com.android.library' +plugins { + id("com.android.library") +} android { namespace = "io.flutter.plugins.googlemaps" @@ -33,7 +35,7 @@ android { lint { checkAllWarnings = true warningsAsErrors = true - disable 'AndroidGradlePluginVersion', 'InvalidPackage', 'GradleDependency', 'NewerVersionAvailable' + disable.addAll(setOf("AndroidGradlePluginVersion", "InvalidPackage", "GradleDependency", "NewerVersionAvailable")) } dependencies { @@ -55,19 +57,21 @@ android { } testOptions { - unitTests.includeAndroidResources = true - unitTests.returnDefaultValues = true - unitTests.all { - testLogging { - events "passed", "skipped", "failed", "standardOut", "standardError" - outputs.upToDateWhen {false} - showStandardStreams = true + unitTests { + isIncludeAndroidResources = true + isReturnDefaultValues = true + all { + it.outputs.upToDateWhen { false } + it.testLogging { + events("passed", "skipped", "failed", "standardOut", "standardError") + showStandardStreams = true + } + // The org.gradle.jvmargs property that may be set in gradle.properties does not impact + // the Java heap size when running the Android unit tests. The following property here + // sets the heap size to a size large enough to run the robolectric tests across + // multiple SDK levels. + it.jvmArgs("-Xmx4G") } - // The org.gradle.jvmargs property that may be set in gradle.properties does not impact - // the Java heap size when running the Android unit tests. The following property here - // sets the heap size to a size large enough to run the robolectric tests across - // multiple SDK levels. - jvmArgs "-Xmx4G" } } } diff --git a/packages/google_maps_flutter/google_maps_flutter_android/android/settings.gradle b/packages/google_maps_flutter/google_maps_flutter_android/android/settings.gradle deleted file mode 100644 index d873c7abe92c..000000000000 --- a/packages/google_maps_flutter/google_maps_flutter_android/android/settings.gradle +++ /dev/null @@ -1 +0,0 @@ -rootProject.name = 'google_maps_flutter_android' diff --git a/packages/google_maps_flutter/google_maps_flutter_android/android/settings.gradle.kts b/packages/google_maps_flutter/google_maps_flutter_android/android/settings.gradle.kts new file mode 100644 index 000000000000..8a4acb4d1530 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_android/android/settings.gradle.kts @@ -0,0 +1 @@ +rootProject.name = "google_maps_flutter_android" diff --git a/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/AndroidManifest.xml b/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/AndroidManifest.xml index d1886695e47c..aca304ed7f76 100644 --- a/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/AndroidManifest.xml +++ b/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/AndroidManifest.xml @@ -1,3 +1,6 @@ + + + diff --git a/packages/google_maps_flutter/google_maps_flutter_android/pubspec.yaml b/packages/google_maps_flutter/google_maps_flutter_android/pubspec.yaml index 817e60a672ae..748e38273331 100644 --- a/packages/google_maps_flutter/google_maps_flutter_android/pubspec.yaml +++ b/packages/google_maps_flutter/google_maps_flutter_android/pubspec.yaml @@ -2,7 +2,7 @@ name: google_maps_flutter_android description: Android implementation of the google_maps_flutter plugin. repository: https://github.com/flutter/packages/tree/main/packages/google_maps_flutter/google_maps_flutter_android issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+maps%22 -version: 2.19.3 +version: 2.19.5 environment: sdk: ^3.9.0 diff --git a/packages/google_maps_flutter/google_maps_flutter_ios/CHANGELOG.md b/packages/google_maps_flutter/google_maps_flutter_ios/CHANGELOG.md index 53957aa91377..179691037daf 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios/CHANGELOG.md +++ b/packages/google_maps_flutter/google_maps_flutter_ios/CHANGELOG.md @@ -1,3 +1,7 @@ +## 2.18.1 + +* Removes conditional header logic that broke add-to-app builds. + ## 2.18.0 * Adds support for advanced markers. diff --git a/packages/google_maps_flutter/google_maps_flutter_ios/ios/google_maps_flutter_ios.podspec b/packages/google_maps_flutter/google_maps_flutter_ios/ios/google_maps_flutter_ios.podspec index 529c229438cd..d18e53fac837 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios/ios/google_maps_flutter_ios.podspec +++ b/packages/google_maps_flutter/google_maps_flutter_ios/ios/google_maps_flutter_ios.podspec @@ -38,8 +38,6 @@ Downloaded by pub (not CocoaPods). s.xcconfig = { 'LIBRARY_SEARCH_PATHS' => '$(inherited) $(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME)/ $(SDKROOT)/usr/lib/swift', 'LD_RUNPATH_SEARCH_PATHS' => '$(inherited) /usr/lib/swift', - # To handle the difference in framework names between CocoaPods and Swift Package Manager in shared code. - 'GCC_PREPROCESSOR_DEFINITIONS' => '$(inherited) FGM_USING_COCOAPODS=1', } s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES' } s.resource_bundles = {'google_maps_flutter_ios_privacy' => ['google_maps_flutter_ios/Sources/google_maps_flutter_ios/Resources/PrivacyInfo.xcprivacy']} diff --git a/packages/google_maps_flutter/google_maps_flutter_ios/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/include/google_maps_flutter_ios/GoogleMapsUtilsTrampoline.h b/packages/google_maps_flutter/google_maps_flutter_ios/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/include/google_maps_flutter_ios/GoogleMapsUtilsTrampoline.h index cf6399b5b39e..f28daee88163 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/include/google_maps_flutter_ios/GoogleMapsUtilsTrampoline.h +++ b/packages/google_maps_flutter/google_maps_flutter_ios/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/include/google_maps_flutter_ios/GoogleMapsUtilsTrampoline.h @@ -2,11 +2,4 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// If Swift Package Manager is in use, Objective-C headers are available under the -// GoogleMapsUtilsObjC package. When using CocoaPods, the headers are provided by the -// GoogleMapsUtils package. -#ifdef FGM_USING_COCOAPODS @import GoogleMapsUtils; -#else -@import GoogleMapsUtilsObjC; -#endif diff --git a/packages/google_maps_flutter/google_maps_flutter_ios/pubspec.yaml b/packages/google_maps_flutter/google_maps_flutter_ios/pubspec.yaml index 6b01ee3376a9..d8548ac8dac0 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios/pubspec.yaml +++ b/packages/google_maps_flutter/google_maps_flutter_ios/pubspec.yaml @@ -2,7 +2,7 @@ name: google_maps_flutter_ios description: iOS implementation of the google_maps_flutter plugin. repository: https://github.com/flutter/packages/tree/main/packages/google_maps_flutter/google_maps_flutter_ios issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+maps%22 -version: 2.18.0 +version: 2.18.1 environment: sdk: ^3.10.0 diff --git a/packages/google_maps_flutter/google_maps_flutter_ios/tool/unshared_source_files.dart b/packages/google_maps_flutter/google_maps_flutter_ios/tool/unshared_source_files.dart index 90d963c64dde..627f7e007ee0 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios/tool/unshared_source_files.dart +++ b/packages/google_maps_flutter/google_maps_flutter_ios/tool/unshared_source_files.dart @@ -10,4 +10,6 @@ const intentionallyUnsharedSourceFiles = [ 'test/package_specific_test_import.dart', // Each package will have its own list. 'tool/unshared_source_files.dart', + // Unshared due to https://github.com/flutter/flutter/issues/183441. + 'ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/include/google_maps_flutter_ios/GoogleMapsUtilsTrampoline.h', ]; diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/tool/unshared_source_files.dart b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/tool/unshared_source_files.dart index 8660b7e6a17e..dee386df465d 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/tool/unshared_source_files.dart +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/tool/unshared_source_files.dart @@ -12,4 +12,6 @@ const intentionallyUnsharedSourceFiles = [ 'test/package_specific_test_import.dart', // Each package will have its own list. 'tool/unshared_source_files.dart', + // Unshared due to https://github.com/flutter/flutter/issues/183441. + 'ios/google_maps_flutter_ios_sdk10/Sources/google_maps_flutter_ios_sdk10/include/google_maps_flutter_ios_sdk10/GoogleMapsUtilsTrampoline.h', ]; diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/tool/unshared_source_files.dart b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/tool/unshared_source_files.dart index 1cfb85a852ac..7e0205065261 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/tool/unshared_source_files.dart +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/tool/unshared_source_files.dart @@ -12,4 +12,6 @@ const intentionallyUnsharedSourceFiles = [ 'test/package_specific_test_import.dart', // Each package will have its own list. 'tool/unshared_source_files.dart', + // Unshared due to https://github.com/flutter/flutter/issues/183441. + 'ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/GoogleMapsUtilsTrampoline.h', ]; diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/include/google_maps_flutter_ios/GoogleMapsUtilsTrampoline.h b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/include/google_maps_flutter_ios/GoogleMapsUtilsTrampoline.h deleted file mode 100644 index cf6399b5b39e..000000000000 --- a/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/include/google_maps_flutter_ios/GoogleMapsUtilsTrampoline.h +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright 2013 The Flutter Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// If Swift Package Manager is in use, Objective-C headers are available under the -// GoogleMapsUtilsObjC package. When using CocoaPods, the headers are provided by the -// GoogleMapsUtils package. -#ifdef FGM_USING_COCOAPODS -@import GoogleMapsUtils; -#else -@import GoogleMapsUtilsObjC; -#endif diff --git a/packages/google_sign_in/google_sign_in_android/CHANGELOG.md b/packages/google_sign_in/google_sign_in_android/CHANGELOG.md index 38624c575a70..0117c25f07d9 100644 --- a/packages/google_sign_in/google_sign_in_android/CHANGELOG.md +++ b/packages/google_sign_in/google_sign_in_android/CHANGELOG.md @@ -1,3 +1,7 @@ +## 7.2.10 + +* Updates build files from Groovy to Kotlin. + ## 7.2.9 * Simplifies internal code for Kotlin/Java interoperability. diff --git a/packages/google_sign_in/google_sign_in_android/android/build.gradle b/packages/google_sign_in/google_sign_in_android/android/build.gradle.kts similarity index 63% rename from packages/google_sign_in/google_sign_in_android/android/build.gradle rename to packages/google_sign_in/google_sign_in_android/android/build.gradle.kts index cd786af0b9c8..4ee50f996d19 100644 --- a/packages/google_sign_in/google_sign_in_android/android/build.gradle +++ b/packages/google_sign_in/google_sign_in_android/android/build.gradle.kts @@ -1,8 +1,10 @@ +import org.jetbrains.kotlin.gradle.dsl.JvmTarget + group = "io.flutter.plugins.googlesignin" version = "1.0-SNAPSHOT" buildscript { - ext.kotlin_version = '2.3.0' + val kotlinVersion = "2.3.0" repositories { google() mavenCentral() @@ -10,19 +12,27 @@ buildscript { dependencies { classpath("com.android.tools.build:gradle:8.13.1") - classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version") + classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion") } } -rootProject.allprojects { +allprojects { repositories { google() mavenCentral() } } -apply plugin: 'com.android.library' -apply plugin: 'kotlin-android' +plugins { + id("com.android.library") + id("kotlin-android") +} + +kotlin { + compilerOptions { + jvmTarget = JvmTarget.fromTarget(JavaVersion.VERSION_17.toString()) + } +} android { namespace = "io.flutter.plugins.googlesignin" @@ -38,29 +48,23 @@ android { targetCompatibility = JavaVersion.VERSION_17 } - kotlinOptions { - jvmTarget = JavaVersion.VERSION_17.toString() - } - - sourceSets { - main.java.srcDirs += 'src/main/kotlin' - } - lint { checkAllWarnings = true warningsAsErrors = true - disable 'AndroidGradlePluginVersion', 'InvalidPackage', 'GradleDependency', 'NewerVersionAvailable' + disable.addAll(setOf("AndroidGradlePluginVersion", "InvalidPackage", "GradleDependency", "NewerVersionAvailable")) baseline = file("lint-baseline.xml") } testOptions { - unitTests.includeAndroidResources = true - unitTests.returnDefaultValues = true - unitTests.all { - testLogging { - events "passed", "skipped", "failed", "standardOut", "standardError" - outputs.upToDateWhen {false} - showStandardStreams = true + unitTests { + isIncludeAndroidResources = true + isReturnDefaultValues = true + all { + it.outputs.upToDateWhen { false } + it.testLogging { + events("passed", "skipped", "failed", "standardOut", "standardError") + showStandardStreams = true + } } } } diff --git a/packages/google_sign_in/google_sign_in_android/android/settings.gradle b/packages/google_sign_in/google_sign_in_android/android/settings.gradle deleted file mode 100644 index 35ebd0e2428a..000000000000 --- a/packages/google_sign_in/google_sign_in_android/android/settings.gradle +++ /dev/null @@ -1 +0,0 @@ -rootProject.name = 'google_sign_in_android' diff --git a/packages/google_sign_in/google_sign_in_android/android/settings.gradle.kts b/packages/google_sign_in/google_sign_in_android/android/settings.gradle.kts new file mode 100644 index 000000000000..88f95d9cc61f --- /dev/null +++ b/packages/google_sign_in/google_sign_in_android/android/settings.gradle.kts @@ -0,0 +1 @@ +rootProject.name = "google_sign_in_android" diff --git a/packages/google_sign_in/google_sign_in_android/pubspec.yaml b/packages/google_sign_in/google_sign_in_android/pubspec.yaml index 244cf1d3f6fd..ead6b61afa4a 100644 --- a/packages/google_sign_in/google_sign_in_android/pubspec.yaml +++ b/packages/google_sign_in/google_sign_in_android/pubspec.yaml @@ -2,7 +2,7 @@ name: google_sign_in_android description: Android implementation of the google_sign_in plugin. repository: https://github.com/flutter/packages/tree/main/packages/google_sign_in/google_sign_in_android issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+google_sign_in%22 -version: 7.2.9 +version: 7.2.10 environment: sdk: ^3.9.0 diff --git a/packages/image_picker/image_picker_android/CHANGELOG.md b/packages/image_picker/image_picker_android/CHANGELOG.md index 7f2e33347447..80d91b1deb87 100644 --- a/packages/image_picker/image_picker_android/CHANGELOG.md +++ b/packages/image_picker/image_picker_android/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.8.13+15 + +* Updates build files from Groovy to Kotlin. + ## 0.8.13+14 * Bumps androidx.activity:activity from 1.12.2 to 1.12.4. diff --git a/packages/image_picker/image_picker_android/android/build.gradle b/packages/image_picker/image_picker_android/android/build.gradle.kts similarity index 70% rename from packages/image_picker/image_picker_android/android/build.gradle rename to packages/image_picker/image_picker_android/android/build.gradle.kts index f92f828f1321..c60f5f0bdaf2 100644 --- a/packages/image_picker/image_picker_android/android/build.gradle +++ b/packages/image_picker/image_picker_android/android/build.gradle.kts @@ -12,14 +12,16 @@ buildscript { } } -rootProject.allprojects { +allprojects { repositories { google() mavenCentral() } } -apply plugin: 'com.android.library' +plugins { + id("com.android.library") +} android { namespace = "io.flutter.plugins.imagepicker" @@ -33,7 +35,7 @@ android { lint { checkAllWarnings = true warningsAsErrors = true - disable 'AndroidGradlePluginVersion', 'InvalidPackage', 'GradleDependency', 'NewerVersionAvailable' + disable.addAll(setOf("AndroidGradlePluginVersion", "InvalidPackage", "GradleDependency", "NewerVersionAvailable")) } dependencies { @@ -54,13 +56,15 @@ android { } testOptions { - unitTests.includeAndroidResources = true - unitTests.returnDefaultValues = true - unitTests.all { - testLogging { - events "passed", "skipped", "failed", "standardOut", "standardError" - outputs.upToDateWhen {false} - showStandardStreams = true + unitTests { + isIncludeAndroidResources = true + isReturnDefaultValues = true + all { + it.outputs.upToDateWhen { false } + it.testLogging { + events("passed", "skipped", "failed", "standardOut", "standardError") + showStandardStreams = true + } } } } diff --git a/packages/image_picker/image_picker_android/android/settings.gradle b/packages/image_picker/image_picker_android/android/settings.gradle deleted file mode 100755 index 3c673efcd542..000000000000 --- a/packages/image_picker/image_picker_android/android/settings.gradle +++ /dev/null @@ -1 +0,0 @@ -rootProject.name = 'image_picker_android' diff --git a/packages/image_picker/image_picker_android/android/settings.gradle.kts b/packages/image_picker/image_picker_android/android/settings.gradle.kts new file mode 100755 index 000000000000..efd9fe9f7500 --- /dev/null +++ b/packages/image_picker/image_picker_android/android/settings.gradle.kts @@ -0,0 +1 @@ +rootProject.name = "image_picker_android" diff --git a/packages/image_picker/image_picker_android/pubspec.yaml b/packages/image_picker/image_picker_android/pubspec.yaml index 37dfcbaf8654..aba9ecbef800 100755 --- a/packages/image_picker/image_picker_android/pubspec.yaml +++ b/packages/image_picker/image_picker_android/pubspec.yaml @@ -2,7 +2,7 @@ name: image_picker_android description: Android implementation of the image_picker plugin. repository: https://github.com/flutter/packages/tree/main/packages/image_picker/image_picker_android issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+image_picker%22 -version: 0.8.13+14 +version: 0.8.13+15 environment: sdk: ^3.9.0 diff --git a/packages/in_app_purchase/in_app_purchase_android/CHANGELOG.md b/packages/in_app_purchase/in_app_purchase_android/CHANGELOG.md index 5769150bf7fb..88c613231c8a 100644 --- a/packages/in_app_purchase/in_app_purchase_android/CHANGELOG.md +++ b/packages/in_app_purchase/in_app_purchase_android/CHANGELOG.md @@ -1,3 +1,11 @@ +## 0.4.0+10 + +* Fixes dartdoc comments that accidentally used HTML. + +## 0.4.0+9 + +* Updates build files from Groovy to Kotlin. + ## 0.4.0+8 * Bumps com.android.tools.build:gradle from 8.12.1 to 8.13.1. diff --git a/packages/in_app_purchase/in_app_purchase_android/android/build.gradle b/packages/in_app_purchase/in_app_purchase_android/android/build.gradle.kts similarity index 72% rename from packages/in_app_purchase/in_app_purchase_android/android/build.gradle rename to packages/in_app_purchase/in_app_purchase_android/android/build.gradle.kts index 179938c5c3ad..adfb82752f56 100644 --- a/packages/in_app_purchase/in_app_purchase_android/android/build.gradle +++ b/packages/in_app_purchase/in_app_purchase_android/android/build.gradle.kts @@ -12,14 +12,16 @@ buildscript { } } -rootProject.allprojects { +allprojects { repositories { google() mavenCentral() } } -apply plugin: 'com.android.library' +plugins { + id("com.android.library") +} android { buildFeatures { @@ -38,7 +40,7 @@ android { lint { checkAllWarnings = true warningsAsErrors = true - disable 'AndroidGradlePluginVersion', 'InvalidPackage', 'GradleDependency', 'NewerVersionAvailable' + disable.addAll(setOf("AndroidGradlePluginVersion", "InvalidPackage", "GradleDependency", "NewerVersionAvailable")) } compileOptions { @@ -47,13 +49,15 @@ android { } testOptions { - unitTests.includeAndroidResources = true - unitTests.returnDefaultValues = true - unitTests.all { - testLogging { - events "passed", "skipped", "failed", "standardOut", "standardError" - outputs.upToDateWhen {false} - showStandardStreams = true + unitTests { + isIncludeAndroidResources = true + isReturnDefaultValues = true + all { + it.outputs.upToDateWhen { false } + it.testLogging { + events("passed", "skipped", "failed", "standardOut", "standardError") + showStandardStreams = true + } } } } diff --git a/packages/in_app_purchase/in_app_purchase_android/android/settings.gradle b/packages/in_app_purchase/in_app_purchase_android/android/settings.gradle deleted file mode 100644 index 58efd2e9323e..000000000000 --- a/packages/in_app_purchase/in_app_purchase_android/android/settings.gradle +++ /dev/null @@ -1 +0,0 @@ -rootProject.name = 'in_app_purchase' diff --git a/packages/in_app_purchase/in_app_purchase_android/android/settings.gradle.kts b/packages/in_app_purchase/in_app_purchase_android/android/settings.gradle.kts new file mode 100644 index 000000000000..9d77dc602791 --- /dev/null +++ b/packages/in_app_purchase/in_app_purchase_android/android/settings.gradle.kts @@ -0,0 +1 @@ +rootProject.name = "in_app_purchase" diff --git a/packages/in_app_purchase/in_app_purchase_android/pigeons/messages.dart b/packages/in_app_purchase/in_app_purchase_android/pigeons/messages.dart index 90f987cc8dfc..c1e04bffdeb7 100644 --- a/packages/in_app_purchase/in_app_purchase_android/pigeons/messages.dart +++ b/packages/in_app_purchase/in_app_purchase_android/pigeons/messages.dart @@ -447,12 +447,12 @@ abstract class InAppPurchaseApi { @FlutterApi() abstract class InAppPurchaseCallbackApi { - /// Called for BillingClientStateListener#onBillingServiceDisconnected(). + /// Called for `BillingClientStateListener#onBillingServiceDisconnected()`. void onBillingServiceDisconnected(int callbackHandle); - /// Called for PurchasesUpdatedListener#onPurchasesUpdated(BillingResult, List). + /// Called for `PurchasesUpdatedListener#onPurchasesUpdated(BillingResult, List)`. void onPurchasesUpdated(PlatformPurchasesResponse update); - /// Called for UserChoiceBillingListener#userSelectedAlternativeBilling(UserChoiceDetails). + /// Called for `UserChoiceBillingListener#userSelectedAlternativeBilling(UserChoiceDetails)`. void userSelectedalternativeBilling(PlatformUserChoiceDetails details); } diff --git a/packages/in_app_purchase/in_app_purchase_android/pubspec.yaml b/packages/in_app_purchase/in_app_purchase_android/pubspec.yaml index 06a91eb3cfaa..9eb1a5547583 100644 --- a/packages/in_app_purchase/in_app_purchase_android/pubspec.yaml +++ b/packages/in_app_purchase/in_app_purchase_android/pubspec.yaml @@ -2,8 +2,7 @@ name: in_app_purchase_android description: An implementation for the Android platform of the Flutter `in_app_purchase` plugin. This uses the Android BillingClient APIs. repository: https://github.com/flutter/packages/tree/main/packages/in_app_purchase/in_app_purchase_android issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+in_app_purchase%22 - -version: 0.4.0+8 +version: 0.4.0+10 environment: sdk: ^3.9.0 diff --git a/packages/in_app_purchase/in_app_purchase_storekit/example/shared/RunnerTests/InAppPurchaseStoreKit2PluginTests.swift b/packages/in_app_purchase/in_app_purchase_storekit/example/shared/RunnerTests/InAppPurchaseStoreKit2PluginTests.swift index 88abb2ff063d..6440b374e41b 100644 --- a/packages/in_app_purchase/in_app_purchase_storekit/example/shared/RunnerTests/InAppPurchaseStoreKit2PluginTests.swift +++ b/packages/in_app_purchase/in_app_purchase_storekit/example/shared/RunnerTests/InAppPurchaseStoreKit2PluginTests.swift @@ -181,6 +181,13 @@ final class InAppPurchase2PluginTests: XCTestCase { //TODO(louisehsu): Add testing for lower versions. @available(iOS 17.0, macOS 14.0, *) func testGetProductsWithStoreKitError() async throws { + let osVersion = ProcessInfo.processInfo.operatingSystemVersion + try XCTSkipIf( + // https://developer.apple.com/forums/thread/808030 + osVersion.majorVersion == 26 && osVersion.minorVersion == 2, + "Known StoreKitTest bug on Xcode 26.2 with setSimulatedError() when used on .loadProducts API" + ) + try await session.setSimulatedError( .generic(.networkError(URLError(.badURL))), forAPI: .loadProducts) @@ -217,6 +224,15 @@ final class InAppPurchase2PluginTests: XCTestCase { @available(iOS 17.0, macOS 14.0, *) func testFailedNetworkErrorPurchase() async throws { + let osVersion = ProcessInfo.processInfo.operatingSystemVersion + try XCTSkipIf( + // https://developer.apple.com/forums/thread/808030 + osVersion.majorVersion == 26 && osVersion.minorVersion == 2, + "Known StoreKitTest bug on Xcode 26.2 with setSimulatedError() when used on .loadProducts API" + ) + + // StoreKitTest aggressively caches products and transaction, which means sometimes it bypasses a simulated error. + session.clearTransactions() try await session.setSimulatedError( .generic(.networkError(URLError(.badURL))), forAPI: .loadProducts) let expectation = self.expectation(description: "products request should fail") @@ -290,7 +306,7 @@ final class InAppPurchase2PluginTests: XCTestCase { XCTFail("Purchase should NOT fail. Failed with \(error)") } } - await fulfillment(of: [expectation], timeout: 5) + await fulfillment(of: [expectation], timeout: 10) } func testDiscountedProductSuccess() async throws { @@ -303,7 +319,7 @@ final class InAppPurchase2PluginTests: XCTestCase { XCTFail("Purchase should NOT fail. Failed with \(error)") } } - await fulfillment(of: [expectation], timeout: 5) + await fulfillment(of: [expectation], timeout: 10) } func testPurchaseWithAppAccountToken() async throws { diff --git a/packages/in_app_purchase/in_app_purchase_storekit/example/shared/RunnerTests/Stubs.m b/packages/in_app_purchase/in_app_purchase_storekit/example/shared/RunnerTests/Stubs.m index 51a31d9fc286..b3e0891d3f62 100644 --- a/packages/in_app_purchase/in_app_purchase_storekit/example/shared/RunnerTests/Stubs.m +++ b/packages/in_app_purchase/in_app_purchase_storekit/example/shared/RunnerTests/Stubs.m @@ -607,9 +607,11 @@ - (void)registerViewFactory:(nonnull NSObject *)fact } } -// TODO(stuartmorgan): Make this NSObject once -// FlutterSceneLifeCycleDelegate has reached stable. -- (void)addSceneDelegate:(nonnull NSObject *)delegate { +- (void)addSceneDelegate:(nonnull NSObject *)delegate { +} + +- (nullable NSObject *)valuePublishedByPlugin:(nonnull NSString *)pluginKey { + return nil; } @end diff --git a/packages/interactive_media_ads/CHANGELOG.md b/packages/interactive_media_ads/CHANGELOG.md index 96ae9a06e90f..f3e56c233359 100644 --- a/packages/interactive_media_ads/CHANGELOG.md +++ b/packages/interactive_media_ads/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.3.0+13 + +* Updates build files from Groovy to Kotlin. + ## 0.3.0+12 * Bumps `androidx.core:core-ktx` from 1.13.0 to 1.18.0. diff --git a/packages/interactive_media_ads/android/build.gradle b/packages/interactive_media_ads/android/build.gradle.kts similarity index 63% rename from packages/interactive_media_ads/android/build.gradle rename to packages/interactive_media_ads/android/build.gradle.kts index 605eae7dd14b..a9ef29108629 100644 --- a/packages/interactive_media_ads/android/build.gradle +++ b/packages/interactive_media_ads/android/build.gradle.kts @@ -1,8 +1,10 @@ +import org.jetbrains.kotlin.gradle.dsl.JvmTarget + group = "dev.flutter.packages.interactive_media_ads" version = "1.0-SNAPSHOT" buildscript { - ext.kotlin_version = '2.3.0' + val kotlinVersion = "2.3.0" repositories { google() mavenCentral() @@ -10,7 +12,7 @@ buildscript { dependencies { classpath("com.android.tools.build:gradle:8.13.1") - classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version") + classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion") } } @@ -21,8 +23,16 @@ allprojects { } } -apply plugin: 'com.android.library' -apply plugin: 'kotlin-android' +plugins { + id("com.android.library") + id("kotlin-android") +} + +kotlin { + compilerOptions { + jvmTarget = JvmTarget.fromTarget(JavaVersion.VERSION_17.toString()) + } +} android { namespace = "dev.flutter.packages.interactive_media_ads" @@ -34,15 +44,6 @@ android { targetCompatibility = JavaVersion.VERSION_17 } - kotlinOptions { - jvmTarget = JavaVersion.VERSION_17.toString() - } - - sourceSets { - main.java.srcDirs += 'src/main/kotlin' - test.java.srcDirs += 'src/test/kotlin' - } - defaultConfig { minSdk = 24 } @@ -61,19 +62,21 @@ android { lint { checkAllWarnings = true warningsAsErrors = true - disable 'AndroidGradlePluginVersion', 'InvalidPackage', 'GradleDependency', 'NewerVersionAvailable' + disable.addAll(setOf("AndroidGradlePluginVersion", "InvalidPackage", "GradleDependency", "NewerVersionAvailable")) baseline = file("lint-baseline.xml") } testOptions { - unitTests.includeAndroidResources = true - unitTests.returnDefaultValues = true - unitTests.all { - useJUnitPlatform() - testLogging { - events "passed", "skipped", "failed", "standardOut", "standardError" - outputs.upToDateWhen {false} - showStandardStreams = true + unitTests { + isIncludeAndroidResources = true + isReturnDefaultValues = true + all { + it.useJUnitPlatform() + it.outputs.upToDateWhen { false } + it.testLogging { + events("passed", "skipped", "failed", "standardOut", "standardError") + showStandardStreams = true + } } } } diff --git a/packages/interactive_media_ads/android/settings.gradle b/packages/interactive_media_ads/android/settings.gradle deleted file mode 100644 index 388e84d5a359..000000000000 --- a/packages/interactive_media_ads/android/settings.gradle +++ /dev/null @@ -1 +0,0 @@ -rootProject.name = 'interactive_media_ads' diff --git a/packages/interactive_media_ads/android/settings.gradle.kts b/packages/interactive_media_ads/android/settings.gradle.kts new file mode 100644 index 000000000000..3e483db7158d --- /dev/null +++ b/packages/interactive_media_ads/android/settings.gradle.kts @@ -0,0 +1 @@ +rootProject.name = "interactive_media_ads" diff --git a/packages/interactive_media_ads/android/src/main/kotlin/dev/flutter/packages/interactive_media_ads/AdsRequestProxyApi.kt b/packages/interactive_media_ads/android/src/main/kotlin/dev/flutter/packages/interactive_media_ads/AdsRequestProxyApi.kt index a9a6b4106656..9ecf4f41c04f 100644 --- a/packages/interactive_media_ads/android/src/main/kotlin/dev/flutter/packages/interactive_media_ads/AdsRequestProxyApi.kt +++ b/packages/interactive_media_ads/android/src/main/kotlin/dev/flutter/packages/interactive_media_ads/AdsRequestProxyApi.kt @@ -21,7 +21,7 @@ class AdsRequestProxyApi(override val pigeonRegistrar: ProxyApiRegistrar) : * * This must match the version in pubspec.yaml. */ - const val pluginVersion = "0.3.0+12" + const val pluginVersion = "0.3.0+13" } override fun setAdTagUrl(pigeon_instance: AdsRequest, adTagUrl: String) { diff --git a/packages/interactive_media_ads/ios/interactive_media_ads/Sources/interactive_media_ads/AdsRequestProxyAPIDelegate.swift b/packages/interactive_media_ads/ios/interactive_media_ads/Sources/interactive_media_ads/AdsRequestProxyAPIDelegate.swift index a0074f86e1c2..c9c0982339b9 100644 --- a/packages/interactive_media_ads/ios/interactive_media_ads/Sources/interactive_media_ads/AdsRequestProxyAPIDelegate.swift +++ b/packages/interactive_media_ads/ios/interactive_media_ads/Sources/interactive_media_ads/AdsRequestProxyAPIDelegate.swift @@ -13,7 +13,7 @@ class AdsRequestProxyAPIDelegate: PigeonApiDelegateIMAAdsRequest { /// The current version of the `interactive_media_ads` plugin. /// /// This must match the version in pubspec.yaml. - static let pluginVersion = "0.3.0+12" + static let pluginVersion = "0.3.0+13" func pigeonDefaultConstructor( pigeonApi: PigeonApiIMAAdsRequest, adTagUrl: String, adDisplayContainer: IMAAdDisplayContainer, diff --git a/packages/interactive_media_ads/pubspec.yaml b/packages/interactive_media_ads/pubspec.yaml index a9a6d0ea061a..46bf16f56ed8 100644 --- a/packages/interactive_media_ads/pubspec.yaml +++ b/packages/interactive_media_ads/pubspec.yaml @@ -2,7 +2,8 @@ name: interactive_media_ads description: A Flutter plugin for using the Interactive Media Ads SDKs on Android and iOS. repository: https://github.com/flutter/packages/tree/main/packages/interactive_media_ads issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+interactive_media_ads%22 -version: 0.3.0+12 # This must match the version in +version: + 0.3.0+13 # This must match the version in # `android/src/main/kotlin/dev/flutter/packages/interactive_media_ads/AdsRequestProxyApi.kt` and # `ios/interactive_media_ads/Sources/interactive_media_ads/AdsRequestProxyAPIDelegate.swift` diff --git a/packages/metrics_center/CHANGELOG.md b/packages/metrics_center/CHANGELOG.md index 59359e9fef0b..6f1d561d244b 100644 --- a/packages/metrics_center/CHANGELOG.md +++ b/packages/metrics_center/CHANGELOG.md @@ -1,5 +1,6 @@ -## NEXT +## 1.0.15 +* Fixes dartdoc comments that accidentally used HTML. * Updates minimum supported SDK version to Flutter 3.35/Dart 3.9. ## 1.0.14 diff --git a/packages/metrics_center/lib/src/skiaperf.dart b/packages/metrics_center/lib/src/skiaperf.dart index caa57319cd49..7f3b98afee6b 100644 --- a/packages/metrics_center/lib/src/skiaperf.dart +++ b/packages/metrics_center/lib/src/skiaperf.dart @@ -126,7 +126,7 @@ class SkiaPerfPoint extends MetricPoint { ); } - /// In the format of '/' such as 'flutter/flutter' or + /// In the format of `/` such as 'flutter/flutter' or /// 'flutter/engine'. final String githubRepo; diff --git a/packages/metrics_center/pubspec.yaml b/packages/metrics_center/pubspec.yaml index 89e52f6e4e14..04a69d21304f 100644 --- a/packages/metrics_center/pubspec.yaml +++ b/packages/metrics_center/pubspec.yaml @@ -1,5 +1,5 @@ name: metrics_center -version: 1.0.14 +version: 1.0.15 description: Support multiple performance metrics sources/formats and destinations. repository: https://github.com/flutter/packages/tree/main/packages/metrics_center diff --git a/packages/path_provider/path_provider_android/CHANGELOG.md b/packages/path_provider/path_provider_android/CHANGELOG.md index 76f560327b59..106b35fa0676 100644 --- a/packages/path_provider/path_provider_android/CHANGELOG.md +++ b/packages/path_provider/path_provider_android/CHANGELOG.md @@ -1,3 +1,7 @@ +## 2.2.23 + +* Updates build files from Groovy to Kotlin. + ## 2.2.22 * Bumps com.android.tools.build:gradle from 8.12.1 to 8.13.1. diff --git a/packages/path_provider/path_provider_android/android/build.gradle b/packages/path_provider/path_provider_android/android/build.gradle.kts similarity index 62% rename from packages/path_provider/path_provider_android/android/build.gradle rename to packages/path_provider/path_provider_android/android/build.gradle.kts index 6201b8529533..3114e6c6385e 100644 --- a/packages/path_provider/path_provider_android/android/build.gradle +++ b/packages/path_provider/path_provider_android/android/build.gradle.kts @@ -12,14 +12,16 @@ buildscript { } } -rootProject.allprojects { +allprojects { repositories { google() mavenCentral() } } -apply plugin: 'com.android.library' +plugins { + id("com.android.library") +} android { namespace = "io.flutter.plugins.pathprovider" @@ -33,7 +35,7 @@ android { lint { checkAllWarnings = true warningsAsErrors = true - disable 'AndroidGradlePluginVersion', 'InvalidPackage', 'GradleDependency', 'NewerVersionAvailable' + disable.addAll(setOf("AndroidGradlePluginVersion", "InvalidPackage", "GradleDependency", "NewerVersionAvailable")) } compileOptions { @@ -42,13 +44,15 @@ android { } testOptions { - unitTests.includeAndroidResources = true - unitTests.returnDefaultValues = true - unitTests.all { - testLogging { - events "passed", "skipped", "failed", "standardOut", "standardError" - outputs.upToDateWhen {false} - showStandardStreams = true + unitTests { + isIncludeAndroidResources = true + isReturnDefaultValues = true + all { + it.outputs.upToDateWhen { false } + it.testLogging { + events("passed", "skipped", "failed", "standardOut", "standardError") + showStandardStreams = true + } } } } diff --git a/packages/path_provider/path_provider_android/android/settings.gradle b/packages/path_provider/path_provider_android/android/settings.gradle deleted file mode 100644 index 359a57ff9540..000000000000 --- a/packages/path_provider/path_provider_android/android/settings.gradle +++ /dev/null @@ -1 +0,0 @@ -rootProject.name = 'path_provider_android' diff --git a/packages/path_provider/path_provider_android/android/settings.gradle.kts b/packages/path_provider/path_provider_android/android/settings.gradle.kts new file mode 100644 index 000000000000..4fc5bb16d8aa --- /dev/null +++ b/packages/path_provider/path_provider_android/android/settings.gradle.kts @@ -0,0 +1 @@ +rootProject.name = "path_provider_android" diff --git a/packages/path_provider/path_provider_android/pubspec.yaml b/packages/path_provider/path_provider_android/pubspec.yaml index 021a3bf16d66..a5a6380aa24b 100644 --- a/packages/path_provider/path_provider_android/pubspec.yaml +++ b/packages/path_provider/path_provider_android/pubspec.yaml @@ -2,7 +2,7 @@ name: path_provider_android description: Android implementation of the path_provider plugin. repository: https://github.com/flutter/packages/tree/main/packages/path_provider/path_provider_android issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+path_provider%22 -version: 2.2.22 +version: 2.2.23 environment: sdk: ^3.9.0 diff --git a/packages/pigeon/CHANGELOG.md b/packages/pigeon/CHANGELOG.md index 7286aedf68c2..368abc59a80f 100644 --- a/packages/pigeon/CHANGELOG.md +++ b/packages/pigeon/CHANGELOG.md @@ -1,3 +1,21 @@ +## 26.3.3 + +* Updates `analyzer` dependency to support versions 10 through 12. + +## 26.3.2 + +* Updates `analyzer` dependency to support version 10. + +## 26.3.1 + +* Fixes dartdoc comments that accidentally used HTML. + +## 26.3.0 + +* Optimizes and improves data class equality and hashing. +* Changes hashing and equality methods to behave consistently across platforms. +* Adds equality methods to previously unsupported languages. + ## 26.2.3 * Produces a helpful error message when a method return type is missing or an diff --git a/packages/pigeon/example/app/android/app/src/main/java/io/flutter/plugins/Messages.java b/packages/pigeon/example/app/android/app/src/main/java/io/flutter/plugins/Messages.java index 799d468cfb1e..751c1f5dc3b0 100644 --- a/packages/pigeon/example/app/android/app/src/main/java/io/flutter/plugins/Messages.java +++ b/packages/pigeon/example/app/android/app/src/main/java/io/flutter/plugins/Messages.java @@ -19,14 +19,171 @@ import java.lang.annotation.Target; import java.nio.ByteBuffer; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.Map; -import java.util.Objects; /** Generated class from Pigeon. */ @SuppressWarnings({"unused", "unchecked", "CodeBlock2Expr", "RedundantSuppression", "serial"}) public class Messages { + static boolean pigeonDoubleEquals(double a, double b) { + // Normalize -0.0 to 0.0 and handle NaN equality. + return (a == 0.0 ? 0.0 : a) == (b == 0.0 ? 0.0 : b) || (Double.isNaN(a) && Double.isNaN(b)); + } + + static boolean pigeonFloatEquals(float a, float b) { + // Normalize -0.0 to 0.0 and handle NaN equality. + return (a == 0.0f ? 0.0f : a) == (b == 0.0f ? 0.0f : b) || (Float.isNaN(a) && Float.isNaN(b)); + } + + static int pigeonDoubleHashCode(double d) { + // Normalize -0.0 to 0.0 and handle NaN to ensure consistent hash codes. + if (d == 0.0) { + d = 0.0; + } + long bits = Double.doubleToLongBits(d); + return (int) (bits ^ (bits >>> 32)); + } + + static int pigeonFloatHashCode(float f) { + // Normalize -0.0 to 0.0 and handle NaN to ensure consistent hash codes. + if (f == 0.0f) { + f = 0.0f; + } + return Float.floatToIntBits(f); + } + + static boolean pigeonDeepEquals(Object a, Object b) { + if (a == b) { + return true; + } + if (a == null || b == null) { + return false; + } + if (a instanceof byte[] && b instanceof byte[]) { + return Arrays.equals((byte[]) a, (byte[]) b); + } + if (a instanceof int[] && b instanceof int[]) { + return Arrays.equals((int[]) a, (int[]) b); + } + if (a instanceof long[] && b instanceof long[]) { + return Arrays.equals((long[]) a, (long[]) b); + } + if (a instanceof double[] && b instanceof double[]) { + double[] da = (double[]) a; + double[] db = (double[]) b; + if (da.length != db.length) { + return false; + } + for (int i = 0; i < da.length; i++) { + if (!pigeonDoubleEquals(da[i], db[i])) { + return false; + } + } + return true; + } + if (a instanceof List && b instanceof List) { + List listA = (List) a; + List listB = (List) b; + if (listA.size() != listB.size()) { + return false; + } + for (int i = 0; i < listA.size(); i++) { + if (!pigeonDeepEquals(listA.get(i), listB.get(i))) { + return false; + } + } + return true; + } + if (a instanceof Map && b instanceof Map) { + Map mapA = (Map) a; + Map mapB = (Map) b; + if (mapA.size() != mapB.size()) { + return false; + } + for (Map.Entry entryA : mapA.entrySet()) { + Object keyA = entryA.getKey(); + Object valueA = entryA.getValue(); + boolean found = false; + for (Map.Entry entryB : mapB.entrySet()) { + Object keyB = entryB.getKey(); + if (pigeonDeepEquals(keyA, keyB)) { + Object valueB = entryB.getValue(); + if (pigeonDeepEquals(valueA, valueB)) { + found = true; + break; + } else { + return false; + } + } + } + if (!found) { + return false; + } + } + return true; + } + if (a instanceof Double && b instanceof Double) { + return pigeonDoubleEquals((double) a, (double) b); + } + if (a instanceof Float && b instanceof Float) { + return pigeonFloatEquals((float) a, (float) b); + } + return a.equals(b); + } + + static int pigeonDeepHashCode(Object value) { + if (value == null) { + return 0; + } + if (value instanceof byte[]) { + return Arrays.hashCode((byte[]) value); + } + if (value instanceof int[]) { + return Arrays.hashCode((int[]) value); + } + if (value instanceof long[]) { + return Arrays.hashCode((long[]) value); + } + if (value instanceof double[]) { + double[] da = (double[]) value; + int result = 1; + for (double d : da) { + result = 31 * result + pigeonDoubleHashCode(d); + } + return result; + } + if (value instanceof List) { + int result = 1; + for (Object item : (List) value) { + result = 31 * result + pigeonDeepHashCode(item); + } + return result; + } + if (value instanceof Map) { + int result = 0; + for (Map.Entry entry : ((Map) value).entrySet()) { + result += + ((pigeonDeepHashCode(entry.getKey()) * 31) ^ pigeonDeepHashCode(entry.getValue())); + } + return result; + } + if (value instanceof Object[]) { + int result = 1; + for (Object item : (Object[]) value) { + result = 31 * result + pigeonDeepHashCode(item); + } + return result; + } + if (value instanceof Double) { + return pigeonDoubleHashCode((double) value); + } + if (value instanceof Float) { + return pigeonFloatHashCode((float) value); + } + return value.hashCode(); + } /** Error class for passing custom error details to Flutter via a thrown PlatformException. */ public static class FlutterError extends RuntimeException { @@ -142,15 +299,16 @@ public boolean equals(Object o) { return false; } MessageData that = (MessageData) o; - return Objects.equals(name, that.name) - && Objects.equals(description, that.description) - && code.equals(that.code) - && data.equals(that.data); + return pigeonDeepEquals(name, that.name) + && pigeonDeepEquals(description, that.description) + && pigeonDeepEquals(code, that.code) + && pigeonDeepEquals(data, that.data); } @Override public int hashCode() { - return Objects.hash(name, description, code, data); + Object[] fields = new Object[] {getClass(), name, description, code, data}; + return pigeonDeepHashCode(fields); } public static final class Builder { diff --git a/packages/pigeon/example/app/android/app/src/main/kotlin/dev/flutter/pigeon_example_app/EventChannelMessages.g.kt b/packages/pigeon/example/app/android/app/src/main/kotlin/dev/flutter/pigeon_example_app/EventChannelMessages.g.kt index e524f5d5b0cf..9029c9425018 100644 --- a/packages/pigeon/example/app/android/app/src/main/kotlin/dev/flutter/pigeon_example_app/EventChannelMessages.g.kt +++ b/packages/pigeon/example/app/android/app/src/main/kotlin/dev/flutter/pigeon_example_app/EventChannelMessages.g.kt @@ -13,7 +13,36 @@ import java.io.ByteArrayOutputStream import java.nio.ByteBuffer private object EventChannelMessagesPigeonUtils { + fun doubleEquals(a: Double, b: Double): Boolean { + // Normalize -0.0 to 0.0 and handle NaN equality. + return (if (a == 0.0) 0.0 else a) == (if (b == 0.0) 0.0 else b) || (a.isNaN() && b.isNaN()) + } + + fun floatEquals(a: Float, b: Float): Boolean { + // Normalize -0.0 to 0.0 and handle NaN equality. + return (if (a == 0.0f) 0.0f else a) == (if (b == 0.0f) 0.0f else b) || (a.isNaN() && b.isNaN()) + } + + fun doubleHash(d: Double): Int { + // Normalize -0.0 to 0.0 and handle NaN to ensure consistent hash codes. + val normalized = if (d == 0.0) 0.0 else d + val bits = java.lang.Double.doubleToLongBits(normalized) + return (bits xor (bits ushr 32)).toInt() + } + + fun floatHash(f: Float): Int { + // Normalize -0.0 to 0.0 and handle NaN to ensure consistent hash codes. + val normalized = if (f == 0.0f) 0.0f else f + return java.lang.Float.floatToIntBits(normalized) + } + fun deepEquals(a: Any?, b: Any?): Boolean { + if (a === b) { + return true + } + if (a == null || b == null) { + return false + } if (a is ByteArray && b is ByteArray) { return a.contentEquals(b) } @@ -24,20 +53,109 @@ private object EventChannelMessagesPigeonUtils { return a.contentEquals(b) } if (a is DoubleArray && b is DoubleArray) { - return a.contentEquals(b) + if (a.size != b.size) return false + for (i in a.indices) { + if (!doubleEquals(a[i], b[i])) return false + } + return true + } + if (a is FloatArray && b is FloatArray) { + if (a.size != b.size) return false + for (i in a.indices) { + if (!floatEquals(a[i], b[i])) return false + } + return true } if (a is Array<*> && b is Array<*>) { - return a.size == b.size && a.indices.all { deepEquals(a[it], b[it]) } + if (a.size != b.size) return false + for (i in a.indices) { + if (!deepEquals(a[i], b[i])) return false + } + return true } if (a is List<*> && b is List<*>) { - return a.size == b.size && a.indices.all { deepEquals(a[it], b[it]) } + if (a.size != b.size) return false + val iterA = a.iterator() + val iterB = b.iterator() + while (iterA.hasNext() && iterB.hasNext()) { + if (!deepEquals(iterA.next(), iterB.next())) return false + } + return true } if (a is Map<*, *> && b is Map<*, *>) { - return a.size == b.size && - a.all { (b as Map).contains(it.key) && deepEquals(it.value, b[it.key]) } + if (a.size != b.size) return false + for (entry in a) { + val key = entry.key + var found = false + for (bEntry in b) { + if (deepEquals(key, bEntry.key)) { + if (deepEquals(entry.value, bEntry.value)) { + found = true + break + } else { + return false + } + } + } + if (!found) return false + } + return true + } + if (a is Double && b is Double) { + return doubleEquals(a, b) + } + if (a is Float && b is Float) { + return floatEquals(a, b) } return a == b } + + fun deepHash(value: Any?): Int { + return when (value) { + null -> 0 + is ByteArray -> value.contentHashCode() + is IntArray -> value.contentHashCode() + is LongArray -> value.contentHashCode() + is DoubleArray -> { + var result = 1 + for (item in value) { + result = 31 * result + doubleHash(item) + } + result + } + is FloatArray -> { + var result = 1 + for (item in value) { + result = 31 * result + floatHash(item) + } + result + } + is Array<*> -> { + var result = 1 + for (item in value) { + result = 31 * result + deepHash(item) + } + result + } + is List<*> -> { + var result = 1 + for (item in value) { + result = 31 * result + deepHash(item) + } + result + } + is Map<*, *> -> { + var result = 0 + for (entry in value) { + result += ((deepHash(entry.key) * 31) xor deepHash(entry.value)) + } + result + } + is Double -> doubleHash(value) + is Float -> floatHash(value) + else -> value.hashCode() + } + } } /** @@ -61,16 +179,21 @@ data class IntEvent(val data: Long) : PlatformEvent() { } override fun equals(other: Any?): Boolean { - if (other !is IntEvent) { + if (other == null || other.javaClass != javaClass) { return false } if (this === other) { return true } - return EventChannelMessagesPigeonUtils.deepEquals(toList(), other.toList()) + val other = other as IntEvent + return EventChannelMessagesPigeonUtils.deepEquals(this.data, other.data) } - override fun hashCode(): Int = toList().hashCode() + override fun hashCode(): Int { + var result = javaClass.hashCode() + result = 31 * result + EventChannelMessagesPigeonUtils.deepHash(this.data) + return result + } } /** Generated class from Pigeon that represents data sent in messages. */ @@ -89,16 +212,21 @@ data class StringEvent(val data: String) : PlatformEvent() { } override fun equals(other: Any?): Boolean { - if (other !is StringEvent) { + if (other == null || other.javaClass != javaClass) { return false } if (this === other) { return true } - return EventChannelMessagesPigeonUtils.deepEquals(toList(), other.toList()) + val other = other as StringEvent + return EventChannelMessagesPigeonUtils.deepEquals(this.data, other.data) } - override fun hashCode(): Int = toList().hashCode() + override fun hashCode(): Int { + var result = javaClass.hashCode() + result = 31 * result + EventChannelMessagesPigeonUtils.deepHash(this.data) + return result + } } private open class EventChannelMessagesPigeonCodec : StandardMessageCodec() { diff --git a/packages/pigeon/example/app/android/app/src/main/kotlin/dev/flutter/pigeon_example_app/Messages.g.kt b/packages/pigeon/example/app/android/app/src/main/kotlin/dev/flutter/pigeon_example_app/Messages.g.kt index 87f4ef1acf12..f82200d46f0d 100644 --- a/packages/pigeon/example/app/android/app/src/main/kotlin/dev/flutter/pigeon_example_app/Messages.g.kt +++ b/packages/pigeon/example/app/android/app/src/main/kotlin/dev/flutter/pigeon_example_app/Messages.g.kt @@ -35,7 +35,36 @@ private object MessagesPigeonUtils { } } + fun doubleEquals(a: Double, b: Double): Boolean { + // Normalize -0.0 to 0.0 and handle NaN equality. + return (if (a == 0.0) 0.0 else a) == (if (b == 0.0) 0.0 else b) || (a.isNaN() && b.isNaN()) + } + + fun floatEquals(a: Float, b: Float): Boolean { + // Normalize -0.0 to 0.0 and handle NaN equality. + return (if (a == 0.0f) 0.0f else a) == (if (b == 0.0f) 0.0f else b) || (a.isNaN() && b.isNaN()) + } + + fun doubleHash(d: Double): Int { + // Normalize -0.0 to 0.0 and handle NaN to ensure consistent hash codes. + val normalized = if (d == 0.0) 0.0 else d + val bits = java.lang.Double.doubleToLongBits(normalized) + return (bits xor (bits ushr 32)).toInt() + } + + fun floatHash(f: Float): Int { + // Normalize -0.0 to 0.0 and handle NaN to ensure consistent hash codes. + val normalized = if (f == 0.0f) 0.0f else f + return java.lang.Float.floatToIntBits(normalized) + } + fun deepEquals(a: Any?, b: Any?): Boolean { + if (a === b) { + return true + } + if (a == null || b == null) { + return false + } if (a is ByteArray && b is ByteArray) { return a.contentEquals(b) } @@ -46,20 +75,109 @@ private object MessagesPigeonUtils { return a.contentEquals(b) } if (a is DoubleArray && b is DoubleArray) { - return a.contentEquals(b) + if (a.size != b.size) return false + for (i in a.indices) { + if (!doubleEquals(a[i], b[i])) return false + } + return true + } + if (a is FloatArray && b is FloatArray) { + if (a.size != b.size) return false + for (i in a.indices) { + if (!floatEquals(a[i], b[i])) return false + } + return true } if (a is Array<*> && b is Array<*>) { - return a.size == b.size && a.indices.all { deepEquals(a[it], b[it]) } + if (a.size != b.size) return false + for (i in a.indices) { + if (!deepEquals(a[i], b[i])) return false + } + return true } if (a is List<*> && b is List<*>) { - return a.size == b.size && a.indices.all { deepEquals(a[it], b[it]) } + if (a.size != b.size) return false + val iterA = a.iterator() + val iterB = b.iterator() + while (iterA.hasNext() && iterB.hasNext()) { + if (!deepEquals(iterA.next(), iterB.next())) return false + } + return true } if (a is Map<*, *> && b is Map<*, *>) { - return a.size == b.size && - a.all { (b as Map).contains(it.key) && deepEquals(it.value, b[it.key]) } + if (a.size != b.size) return false + for (entry in a) { + val key = entry.key + var found = false + for (bEntry in b) { + if (deepEquals(key, bEntry.key)) { + if (deepEquals(entry.value, bEntry.value)) { + found = true + break + } else { + return false + } + } + } + if (!found) return false + } + return true + } + if (a is Double && b is Double) { + return doubleEquals(a, b) + } + if (a is Float && b is Float) { + return floatEquals(a, b) } return a == b } + + fun deepHash(value: Any?): Int { + return when (value) { + null -> 0 + is ByteArray -> value.contentHashCode() + is IntArray -> value.contentHashCode() + is LongArray -> value.contentHashCode() + is DoubleArray -> { + var result = 1 + for (item in value) { + result = 31 * result + doubleHash(item) + } + result + } + is FloatArray -> { + var result = 1 + for (item in value) { + result = 31 * result + floatHash(item) + } + result + } + is Array<*> -> { + var result = 1 + for (item in value) { + result = 31 * result + deepHash(item) + } + result + } + is List<*> -> { + var result = 1 + for (item in value) { + result = 31 * result + deepHash(item) + } + result + } + is Map<*, *> -> { + var result = 0 + for (entry in value) { + result += ((deepHash(entry.key) * 31) xor deepHash(entry.value)) + } + result + } + is Double -> doubleHash(value) + is Float -> floatHash(value) + else -> value.hashCode() + } + } } /** @@ -113,16 +231,27 @@ data class MessageData( } override fun equals(other: Any?): Boolean { - if (other !is MessageData) { + if (other == null || other.javaClass != javaClass) { return false } if (this === other) { return true } - return MessagesPigeonUtils.deepEquals(toList(), other.toList()) + val other = other as MessageData + return MessagesPigeonUtils.deepEquals(this.name, other.name) && + MessagesPigeonUtils.deepEquals(this.description, other.description) && + MessagesPigeonUtils.deepEquals(this.code, other.code) && + MessagesPigeonUtils.deepEquals(this.data, other.data) } - override fun hashCode(): Int = toList().hashCode() + override fun hashCode(): Int { + var result = javaClass.hashCode() + result = 31 * result + MessagesPigeonUtils.deepHash(this.name) + result = 31 * result + MessagesPigeonUtils.deepHash(this.description) + result = 31 * result + MessagesPigeonUtils.deepHash(this.code) + result = 31 * result + MessagesPigeonUtils.deepHash(this.data) + return result + } } private open class MessagesPigeonCodec : StandardMessageCodec() { diff --git a/packages/pigeon/example/app/ios/Runner/EventChannelMessages.g.swift b/packages/pigeon/example/app/ios/Runner/EventChannelMessages.g.swift index 027453c3951e..70cab0a27bec 100644 --- a/packages/pigeon/example/app/ios/Runner/EventChannelMessages.g.swift +++ b/packages/pigeon/example/app/ios/Runner/EventChannelMessages.g.swift @@ -23,6 +23,19 @@ private func nilOrValue(_ value: Any?) -> T? { return value as! T? } +private func doubleEqualsEventChannelMessages(_ lhs: Double, _ rhs: Double) -> Bool { + return (lhs.isNaN && rhs.isNaN) || lhs == rhs +} + +private func doubleHashEventChannelMessages(_ value: Double, _ hasher: inout Hasher) { + if value.isNaN { + hasher.combine(0x7FF8_0000_0000_0000) + } else { + // Normalize -0.0 to 0.0 + hasher.combine(value == 0 ? 0 : value) + } +} + func deepEqualsEventChannelMessages(_ lhs: Any?, _ rhs: Any?) -> Bool { let cleanLhs = nilOrValue(lhs) as Any? let cleanRhs = nilOrValue(rhs) as Any? @@ -33,56 +46,90 @@ func deepEqualsEventChannelMessages(_ lhs: Any?, _ rhs: Any?) -> Bool { case (nil, _), (_, nil): return false - case is (Void, Void): + case (let lhs as AnyObject, let rhs as AnyObject) where lhs === rhs: return true - case let (cleanLhsHashable, cleanRhsHashable) as (AnyHashable, AnyHashable): - return cleanLhsHashable == cleanRhsHashable + case is (Void, Void): + return true - case let (cleanLhsArray, cleanRhsArray) as ([Any?], [Any?]): - guard cleanLhsArray.count == cleanRhsArray.count else { return false } - for (index, element) in cleanLhsArray.enumerated() { - if !deepEqualsEventChannelMessages(element, cleanRhsArray[index]) { + case (let lhsArray, let rhsArray) as ([Any?], [Any?]): + guard lhsArray.count == rhsArray.count else { return false } + for (index, element) in lhsArray.enumerated() { + if !deepEqualsEventChannelMessages(element, rhsArray[index]) { return false } } return true - case let (cleanLhsDictionary, cleanRhsDictionary) as ([AnyHashable: Any?], [AnyHashable: Any?]): - guard cleanLhsDictionary.count == cleanRhsDictionary.count else { return false } - for (key, cleanLhsValue) in cleanLhsDictionary { - guard cleanRhsDictionary.index(forKey: key) != nil else { return false } - if !deepEqualsEventChannelMessages(cleanLhsValue, cleanRhsDictionary[key]!) { + case (let lhsArray, let rhsArray) as ([Double], [Double]): + guard lhsArray.count == rhsArray.count else { return false } + for (index, element) in lhsArray.enumerated() { + if !doubleEqualsEventChannelMessages(element, rhsArray[index]) { return false } } return true + case (let lhsDictionary, let rhsDictionary) as ([AnyHashable: Any?], [AnyHashable: Any?]): + guard lhsDictionary.count == rhsDictionary.count else { return false } + for (lhsKey, lhsValue) in lhsDictionary { + var found = false + for (rhsKey, rhsValue) in rhsDictionary { + if deepEqualsEventChannelMessages(lhsKey, rhsKey) { + if deepEqualsEventChannelMessages(lhsValue, rhsValue) { + found = true + break + } else { + return false + } + } + } + if !found { return false } + } + return true + + case (let lhs as Double, let rhs as Double): + return doubleEqualsEventChannelMessages(lhs, rhs) + + case (let lhsHashable, let rhsHashable) as (AnyHashable, AnyHashable): + return lhsHashable == rhsHashable + default: - // Any other type shouldn't be able to be used with pigeon. File an issue if you find this to be untrue. return false } } func deepHashEventChannelMessages(value: Any?, hasher: inout Hasher) { - if let valueList = value as? [AnyHashable] { - for item in valueList { deepHashEventChannelMessages(value: item, hasher: &hasher) } - return - } - - if let valueDict = value as? [AnyHashable: AnyHashable] { - for key in valueDict.keys { - hasher.combine(key) - deepHashEventChannelMessages(value: valueDict[key]!, hasher: &hasher) + let cleanValue = nilOrValue(value) as Any? + if let cleanValue = cleanValue { + if let doubleValue = cleanValue as? Double { + doubleHashEventChannelMessages(doubleValue, &hasher) + } else if let valueList = cleanValue as? [Any?] { + for item in valueList { + deepHashEventChannelMessages(value: item, hasher: &hasher) + } + } else if let valueList = cleanValue as? [Double] { + for item in valueList { + doubleHashEventChannelMessages(item, &hasher) + } + } else if let valueDict = cleanValue as? [AnyHashable: Any?] { + var result = 0 + for (key, value) in valueDict { + var entryKeyHasher = Hasher() + deepHashEventChannelMessages(value: key, hasher: &entryKeyHasher) + var entryValueHasher = Hasher() + deepHashEventChannelMessages(value: value, hasher: &entryValueHasher) + result = result &+ ((entryKeyHasher.finalize() &* 31) ^ entryValueHasher.finalize()) + } + hasher.combine(result) + } else if let hashableValue = cleanValue as? AnyHashable { + hasher.combine(hashableValue) + } else { + hasher.combine(String(describing: cleanValue)) } - return + } else { + hasher.combine(0) } - - if let hashableValue = value as? AnyHashable { - hasher.combine(hashableValue.hashValue) - } - - return hasher.combine(String(describing: value)) } /// Generated class from Pigeon that represents data sent in messages. @@ -109,10 +156,15 @@ struct IntEvent: PlatformEvent { ] } static func == (lhs: IntEvent, rhs: IntEvent) -> Bool { - return deepEqualsEventChannelMessages(lhs.toList(), rhs.toList()) + if Swift.type(of: lhs) != Swift.type(of: rhs) { + return false + } + return deepEqualsEventChannelMessages(lhs.data, rhs.data) } + func hash(into hasher: inout Hasher) { - deepHashEventChannelMessages(value: toList(), hasher: &hasher) + hasher.combine("IntEvent") + deepHashEventChannelMessages(value: data, hasher: &hasher) } } @@ -134,10 +186,15 @@ struct StringEvent: PlatformEvent { ] } static func == (lhs: StringEvent, rhs: StringEvent) -> Bool { - return deepEqualsEventChannelMessages(lhs.toList(), rhs.toList()) + if Swift.type(of: lhs) != Swift.type(of: rhs) { + return false + } + return deepEqualsEventChannelMessages(lhs.data, rhs.data) } + func hash(into hasher: inout Hasher) { - deepHashEventChannelMessages(value: toList(), hasher: &hasher) + hasher.combine("StringEvent") + deepHashEventChannelMessages(value: data, hasher: &hasher) } } diff --git a/packages/pigeon/example/app/ios/Runner/Messages.g.swift b/packages/pigeon/example/app/ios/Runner/Messages.g.swift index 46c3e23598ef..f8b12f846c22 100644 --- a/packages/pigeon/example/app/ios/Runner/Messages.g.swift +++ b/packages/pigeon/example/app/ios/Runner/Messages.g.swift @@ -53,7 +53,7 @@ private func wrapError(_ error: Any) -> [Any?] { } return [ "\(error)", - "\(type(of: error))", + "\(Swift.type(of: error))", "Stacktrace: \(Thread.callStackSymbols)", ] } @@ -73,6 +73,19 @@ private func nilOrValue(_ value: Any?) -> T? { return value as! T? } +private func doubleEqualsMessages(_ lhs: Double, _ rhs: Double) -> Bool { + return (lhs.isNaN && rhs.isNaN) || lhs == rhs +} + +private func doubleHashMessages(_ value: Double, _ hasher: inout Hasher) { + if value.isNaN { + hasher.combine(0x7FF8_0000_0000_0000) + } else { + // Normalize -0.0 to 0.0 + hasher.combine(value == 0 ? 0 : value) + } +} + func deepEqualsMessages(_ lhs: Any?, _ rhs: Any?) -> Bool { let cleanLhs = nilOrValue(lhs) as Any? let cleanRhs = nilOrValue(rhs) as Any? @@ -83,56 +96,90 @@ func deepEqualsMessages(_ lhs: Any?, _ rhs: Any?) -> Bool { case (nil, _), (_, nil): return false - case is (Void, Void): + case (let lhs as AnyObject, let rhs as AnyObject) where lhs === rhs: return true - case let (cleanLhsHashable, cleanRhsHashable) as (AnyHashable, AnyHashable): - return cleanLhsHashable == cleanRhsHashable + case is (Void, Void): + return true - case let (cleanLhsArray, cleanRhsArray) as ([Any?], [Any?]): - guard cleanLhsArray.count == cleanRhsArray.count else { return false } - for (index, element) in cleanLhsArray.enumerated() { - if !deepEqualsMessages(element, cleanRhsArray[index]) { + case (let lhsArray, let rhsArray) as ([Any?], [Any?]): + guard lhsArray.count == rhsArray.count else { return false } + for (index, element) in lhsArray.enumerated() { + if !deepEqualsMessages(element, rhsArray[index]) { return false } } return true - case let (cleanLhsDictionary, cleanRhsDictionary) as ([AnyHashable: Any?], [AnyHashable: Any?]): - guard cleanLhsDictionary.count == cleanRhsDictionary.count else { return false } - for (key, cleanLhsValue) in cleanLhsDictionary { - guard cleanRhsDictionary.index(forKey: key) != nil else { return false } - if !deepEqualsMessages(cleanLhsValue, cleanRhsDictionary[key]!) { + case (let lhsArray, let rhsArray) as ([Double], [Double]): + guard lhsArray.count == rhsArray.count else { return false } + for (index, element) in lhsArray.enumerated() { + if !doubleEqualsMessages(element, rhsArray[index]) { return false } } return true + case (let lhsDictionary, let rhsDictionary) as ([AnyHashable: Any?], [AnyHashable: Any?]): + guard lhsDictionary.count == rhsDictionary.count else { return false } + for (lhsKey, lhsValue) in lhsDictionary { + var found = false + for (rhsKey, rhsValue) in rhsDictionary { + if deepEqualsMessages(lhsKey, rhsKey) { + if deepEqualsMessages(lhsValue, rhsValue) { + found = true + break + } else { + return false + } + } + } + if !found { return false } + } + return true + + case (let lhs as Double, let rhs as Double): + return doubleEqualsMessages(lhs, rhs) + + case (let lhsHashable, let rhsHashable) as (AnyHashable, AnyHashable): + return lhsHashable == rhsHashable + default: - // Any other type shouldn't be able to be used with pigeon. File an issue if you find this to be untrue. return false } } func deepHashMessages(value: Any?, hasher: inout Hasher) { - if let valueList = value as? [AnyHashable] { - for item in valueList { deepHashMessages(value: item, hasher: &hasher) } - return - } - - if let valueDict = value as? [AnyHashable: AnyHashable] { - for key in valueDict.keys { - hasher.combine(key) - deepHashMessages(value: valueDict[key]!, hasher: &hasher) + let cleanValue = nilOrValue(value) as Any? + if let cleanValue = cleanValue { + if let doubleValue = cleanValue as? Double { + doubleHashMessages(doubleValue, &hasher) + } else if let valueList = cleanValue as? [Any?] { + for item in valueList { + deepHashMessages(value: item, hasher: &hasher) + } + } else if let valueList = cleanValue as? [Double] { + for item in valueList { + doubleHashMessages(item, &hasher) + } + } else if let valueDict = cleanValue as? [AnyHashable: Any?] { + var result = 0 + for (key, value) in valueDict { + var entryKeyHasher = Hasher() + deepHashMessages(value: key, hasher: &entryKeyHasher) + var entryValueHasher = Hasher() + deepHashMessages(value: value, hasher: &entryValueHasher) + result = result &+ ((entryKeyHasher.finalize() &* 31) ^ entryValueHasher.finalize()) + } + hasher.combine(result) + } else if let hashableValue = cleanValue as? AnyHashable { + hasher.combine(hashableValue) + } else { + hasher.combine(String(describing: cleanValue)) } - return - } - - if let hashableValue = value as? AnyHashable { - hasher.combine(hashableValue.hashValue) + } else { + hasher.combine(0) } - - return hasher.combine(String(describing: value)) } enum Code: Int { @@ -170,10 +217,20 @@ struct MessageData: Hashable { ] } static func == (lhs: MessageData, rhs: MessageData) -> Bool { - return deepEqualsMessages(lhs.toList(), rhs.toList()) + if Swift.type(of: lhs) != Swift.type(of: rhs) { + return false + } + return deepEqualsMessages(lhs.name, rhs.name) + && deepEqualsMessages(lhs.description, rhs.description) + && deepEqualsMessages(lhs.code, rhs.code) && deepEqualsMessages(lhs.data, rhs.data) } + func hash(into hasher: inout Hasher) { - deepHashMessages(value: toList(), hasher: &hasher) + hasher.combine("MessageData") + deepHashMessages(value: name, hasher: &hasher) + deepHashMessages(value: description, hasher: &hasher) + deepHashMessages(value: code, hasher: &hasher) + deepHashMessages(value: data, hasher: &hasher) } } diff --git a/packages/pigeon/example/app/lib/src/event_channel_messages.g.dart b/packages/pigeon/example/app/lib/src/event_channel_messages.g.dart index 456b3629f7df..0a31f7b13d7c 100644 --- a/packages/pigeon/example/app/lib/src/event_channel_messages.g.dart +++ b/packages/pigeon/example/app/lib/src/event_channel_messages.g.dart @@ -13,6 +13,15 @@ import 'package:flutter/services.dart'; import 'package:meta/meta.dart' show immutable, protected, visibleForTesting; bool _deepEquals(Object? a, Object? b) { + if (identical(a, b)) { + return true; + } + if (a is double && b is double) { + if (a.isNaN && b.isNaN) { + return true; + } + return a == b; + } if (a is List && b is List) { return a.length == b.length && a.indexed.every( @@ -20,16 +29,52 @@ bool _deepEquals(Object? a, Object? b) { ); } if (a is Map && b is Map) { - return a.length == b.length && - a.entries.every( - (MapEntry entry) => - (b as Map).containsKey(entry.key) && - _deepEquals(entry.value, b[entry.key]), - ); + if (a.length != b.length) { + return false; + } + for (final MapEntry entryA in a.entries) { + bool found = false; + for (final MapEntry entryB in b.entries) { + if (_deepEquals(entryA.key, entryB.key)) { + if (_deepEquals(entryA.value, entryB.value)) { + found = true; + break; + } else { + return false; + } + } + } + if (!found) { + return false; + } + } + return true; } return a == b; } +int _deepHash(Object? value) { + if (value is List) { + return Object.hashAll(value.map(_deepHash)); + } + if (value is Map) { + int result = 0; + for (final MapEntry entry in value.entries) { + result += (_deepHash(entry.key) * 31) ^ _deepHash(entry.value); + } + return result; + } + if (value is double && value.isNaN) { + // Normalize NaN to a consistent hash. + return 0x7FF8000000000000.hashCode; + } + if (value is double && value == 0.0) { + // Normalize -0.0 to 0.0 so they have the same hash code. + return 0.0.hashCode; + } + return value.hashCode; +} + sealed class PlatformEvent {} class IntEvent extends PlatformEvent { @@ -59,12 +104,12 @@ class IntEvent extends PlatformEvent { if (identical(this, other)) { return true; } - return _deepEquals(encode(), other.encode()); + return _deepEquals(data, other.data); } @override // ignore: avoid_equals_and_hash_code_on_mutable_classes - int get hashCode => Object.hashAll(_toList()); + int get hashCode => _deepHash([runtimeType, ..._toList()]); } class StringEvent extends PlatformEvent { @@ -94,12 +139,12 @@ class StringEvent extends PlatformEvent { if (identical(this, other)) { return true; } - return _deepEquals(encode(), other.encode()); + return _deepEquals(data, other.data); } @override // ignore: avoid_equals_and_hash_code_on_mutable_classes - int get hashCode => Object.hashAll(_toList()); + int get hashCode => _deepHash([runtimeType, ..._toList()]); } class _PigeonCodec extends StandardMessageCodec { diff --git a/packages/pigeon/example/app/lib/src/messages.g.dart b/packages/pigeon/example/app/lib/src/messages.g.dart index c876dd35f20a..9efe3e125b07 100644 --- a/packages/pigeon/example/app/lib/src/messages.g.dart +++ b/packages/pigeon/example/app/lib/src/messages.g.dart @@ -52,6 +52,15 @@ List wrapResponse({ } bool _deepEquals(Object? a, Object? b) { + if (identical(a, b)) { + return true; + } + if (a is double && b is double) { + if (a.isNaN && b.isNaN) { + return true; + } + return a == b; + } if (a is List && b is List) { return a.length == b.length && a.indexed.every( @@ -59,16 +68,52 @@ bool _deepEquals(Object? a, Object? b) { ); } if (a is Map && b is Map) { - return a.length == b.length && - a.entries.every( - (MapEntry entry) => - (b as Map).containsKey(entry.key) && - _deepEquals(entry.value, b[entry.key]), - ); + if (a.length != b.length) { + return false; + } + for (final MapEntry entryA in a.entries) { + bool found = false; + for (final MapEntry entryB in b.entries) { + if (_deepEquals(entryA.key, entryB.key)) { + if (_deepEquals(entryA.value, entryB.value)) { + found = true; + break; + } else { + return false; + } + } + } + if (!found) { + return false; + } + } + return true; } return a == b; } +int _deepHash(Object? value) { + if (value is List) { + return Object.hashAll(value.map(_deepHash)); + } + if (value is Map) { + int result = 0; + for (final MapEntry entry in value.entries) { + result += (_deepHash(entry.key) * 31) ^ _deepHash(entry.value); + } + return result; + } + if (value is double && value.isNaN) { + // Normalize NaN to a consistent hash. + return 0x7FF8000000000000.hashCode; + } + if (value is double && value == 0.0) { + // Normalize -0.0 to 0.0 so they have the same hash code. + return 0.0.hashCode; + } + return value.hashCode; +} + enum Code { one, two } class MessageData { @@ -114,12 +159,15 @@ class MessageData { if (identical(this, other)) { return true; } - return _deepEquals(encode(), other.encode()); + return _deepEquals(name, other.name) && + _deepEquals(description, other.description) && + _deepEquals(code, other.code) && + _deepEquals(data, other.data); } @override // ignore: avoid_equals_and_hash_code_on_mutable_classes - int get hashCode => Object.hashAll(_toList()); + int get hashCode => _deepHash([runtimeType, ..._toList()]); } class _PigeonCodec extends StandardMessageCodec { diff --git a/packages/pigeon/example/app/linux/messages.g.cc b/packages/pigeon/example/app/linux/messages.g.cc index 5dc179e4203a..f1b0e818d11f 100644 --- a/packages/pigeon/example/app/linux/messages.g.cc +++ b/packages/pigeon/example/app/linux/messages.g.cc @@ -6,6 +6,197 @@ #include "messages.g.h" +#include + +#include +static guint G_GNUC_UNUSED flpigeon_hash_double(double v) { + if (std::isnan(v)) { + return static_cast(0x7FF80000); + } + if (v == 0.0) { + v = 0.0; + } + union { + double d; + uint64_t u; + } u; + u.d = v; + return static_cast(u.u ^ (u.u >> 32)); +} +static gboolean G_GNUC_UNUSED flpigeon_equals_double(double a, double b) { + return (a == b) || (std::isnan(a) && std::isnan(b)); +} +static gboolean G_GNUC_UNUSED flpigeon_deep_equals(FlValue* a, FlValue* b) { + if (a == b) { + return TRUE; + } + if (a == nullptr || b == nullptr) { + return FALSE; + } + if (fl_value_get_type(a) != fl_value_get_type(b)) { + return FALSE; + } + switch (fl_value_get_type(a)) { + case FL_VALUE_TYPE_NULL: + return TRUE; + case FL_VALUE_TYPE_BOOL: + return fl_value_get_bool(a) == fl_value_get_bool(b); + case FL_VALUE_TYPE_INT: + return fl_value_get_int(a) == fl_value_get_int(b); + case FL_VALUE_TYPE_FLOAT: { + return flpigeon_equals_double(fl_value_get_float(a), + fl_value_get_float(b)); + } + case FL_VALUE_TYPE_STRING: + return g_strcmp0(fl_value_get_string(a), fl_value_get_string(b)) == 0; + case FL_VALUE_TYPE_UINT8_LIST: + return fl_value_get_length(a) == fl_value_get_length(b) && + memcmp(fl_value_get_uint8_list(a), fl_value_get_uint8_list(b), + fl_value_get_length(a)) == 0; + case FL_VALUE_TYPE_INT32_LIST: + return fl_value_get_length(a) == fl_value_get_length(b) && + memcmp(fl_value_get_int32_list(a), fl_value_get_int32_list(b), + fl_value_get_length(a) * sizeof(int32_t)) == 0; + case FL_VALUE_TYPE_INT64_LIST: + return fl_value_get_length(a) == fl_value_get_length(b) && + memcmp(fl_value_get_int64_list(a), fl_value_get_int64_list(b), + fl_value_get_length(a) * sizeof(int64_t)) == 0; + case FL_VALUE_TYPE_FLOAT_LIST: { + size_t len = fl_value_get_length(a); + if (len != fl_value_get_length(b)) { + return FALSE; + } + const double* a_data = fl_value_get_float_list(a); + const double* b_data = fl_value_get_float_list(b); + for (size_t i = 0; i < len; i++) { + if (!flpigeon_equals_double(a_data[i], b_data[i])) { + return FALSE; + } + } + return TRUE; + } + case FL_VALUE_TYPE_LIST: { + size_t len = fl_value_get_length(a); + if (len != fl_value_get_length(b)) { + return FALSE; + } + for (size_t i = 0; i < len; i++) { + if (!flpigeon_deep_equals(fl_value_get_list_value(a, i), + fl_value_get_list_value(b, i))) { + return FALSE; + } + } + return TRUE; + } + case FL_VALUE_TYPE_MAP: { + size_t len = fl_value_get_length(a); + if (len != fl_value_get_length(b)) { + return FALSE; + } + for (size_t i = 0; i < len; i++) { + FlValue* key = fl_value_get_map_key(a, i); + FlValue* val = fl_value_get_map_value(a, i); + gboolean found = FALSE; + for (size_t j = 0; j < len; j++) { + FlValue* b_key = fl_value_get_map_key(b, j); + if (flpigeon_deep_equals(key, b_key)) { + FlValue* b_val = fl_value_get_map_value(b, j); + if (flpigeon_deep_equals(val, b_val)) { + found = TRUE; + break; + } else { + return FALSE; + } + } + } + if (!found) { + return FALSE; + } + } + return TRUE; + } + default: + return FALSE; + } + return FALSE; +} +static guint G_GNUC_UNUSED flpigeon_deep_hash(FlValue* value) { + if (value == nullptr) { + return 0; + } + switch (fl_value_get_type(value)) { + case FL_VALUE_TYPE_NULL: + return 0; + case FL_VALUE_TYPE_BOOL: + return fl_value_get_bool(value) ? 1231 : 1237; + case FL_VALUE_TYPE_INT: { + int64_t v = fl_value_get_int(value); + return static_cast(v ^ (v >> 32)); + } + case FL_VALUE_TYPE_FLOAT: + return flpigeon_hash_double(fl_value_get_float(value)); + case FL_VALUE_TYPE_STRING: + return g_str_hash(fl_value_get_string(value)); + case FL_VALUE_TYPE_UINT8_LIST: { + guint result = 1; + size_t len = fl_value_get_length(value); + const uint8_t* data = fl_value_get_uint8_list(value); + for (size_t i = 0; i < len; i++) { + result = result * 31 + data[i]; + } + return result; + } + case FL_VALUE_TYPE_INT32_LIST: { + guint result = 1; + size_t len = fl_value_get_length(value); + const int32_t* data = fl_value_get_int32_list(value); + for (size_t i = 0; i < len; i++) { + result = result * 31 + static_cast(data[i]); + } + return result; + } + case FL_VALUE_TYPE_INT64_LIST: { + guint result = 1; + size_t len = fl_value_get_length(value); + const int64_t* data = fl_value_get_int64_list(value); + for (size_t i = 0; i < len; i++) { + result = result * 31 + static_cast(data[i] ^ (data[i] >> 32)); + } + return result; + } + case FL_VALUE_TYPE_FLOAT_LIST: { + guint result = 1; + size_t len = fl_value_get_length(value); + const double* data = fl_value_get_float_list(value); + for (size_t i = 0; i < len; i++) { + result = result * 31 + flpigeon_hash_double(data[i]); + } + return result; + } + case FL_VALUE_TYPE_LIST: { + guint result = 1; + size_t len = fl_value_get_length(value); + for (size_t i = 0; i < len; i++) { + result = + result * 31 + flpigeon_deep_hash(fl_value_get_list_value(value, i)); + } + return result; + } + case FL_VALUE_TYPE_MAP: { + guint result = 0; + size_t len = fl_value_get_length(value); + for (size_t i = 0; i < len; i++) { + result += ((flpigeon_deep_hash(fl_value_get_map_key(value, i)) * 31) ^ + flpigeon_deep_hash(fl_value_get_map_value(value, i))); + } + return result; + } + default: + return static_cast(fl_value_get_type(value)); + } + return 0; +} + struct _PigeonExamplePackageMessageData { GObject parent_instance; @@ -119,6 +310,41 @@ pigeon_example_package_message_data_new_from_list(FlValue* values) { return pigeon_example_package_message_data_new(name, description, code, data); } +gboolean pigeon_example_package_message_data_equals( + PigeonExamplePackageMessageData* a, PigeonExamplePackageMessageData* b) { + if (a == b) { + return TRUE; + } + if (a == nullptr || b == nullptr) { + return FALSE; + } + if (g_strcmp0(a->name, b->name) != 0) { + return FALSE; + } + if (g_strcmp0(a->description, b->description) != 0) { + return FALSE; + } + if (a->code != b->code) { + return FALSE; + } + if (!flpigeon_deep_equals(a->data, b->data)) { + return FALSE; + } + return TRUE; +} + +guint pigeon_example_package_message_data_hash( + PigeonExamplePackageMessageData* self) { + g_return_val_if_fail(PIGEON_EXAMPLE_PACKAGE_IS_MESSAGE_DATA(self), 0); + guint result = 0; + result = result * 31 + (self->name != nullptr ? g_str_hash(self->name) : 0); + result = result * 31 + + (self->description != nullptr ? g_str_hash(self->description) : 0); + result = result * 31 + static_cast(self->code); + result = result * 31 + flpigeon_deep_hash(self->data); + return result; +} + struct _PigeonExamplePackageMessageCodec { FlStandardMessageCodec parent_instance; }; diff --git a/packages/pigeon/example/app/linux/messages.g.h b/packages/pigeon/example/app/linux/messages.g.h index 6fb44cc93516..c03ecb20a01d 100644 --- a/packages/pigeon/example/app/linux/messages.g.h +++ b/packages/pigeon/example/app/linux/messages.g.h @@ -90,6 +90,29 @@ PigeonExamplePackageCode pigeon_example_package_message_data_get_code( FlValue* pigeon_example_package_message_data_get_data( PigeonExamplePackageMessageData* object); +/** + * pigeon_example_package_message_data_equals: + * @a: a #PigeonExamplePackageMessageData. + * @b: another #PigeonExamplePackageMessageData. + * + * Checks if two #PigeonExamplePackageMessageData objects are equal. + * + * Returns: TRUE if @a and @b are equal. + */ +gboolean pigeon_example_package_message_data_equals( + PigeonExamplePackageMessageData* a, PigeonExamplePackageMessageData* b); + +/** + * pigeon_example_package_message_data_hash: + * @object: a #PigeonExamplePackageMessageData. + * + * Calculates a hash code for a #PigeonExamplePackageMessageData object. + * + * Returns: the hash code. + */ +guint pigeon_example_package_message_data_hash( + PigeonExamplePackageMessageData* object); + G_DECLARE_FINAL_TYPE(PigeonExamplePackageMessageCodec, pigeon_example_package_message_codec, PIGEON_EXAMPLE_PACKAGE, MESSAGE_CODEC, diff --git a/packages/pigeon/example/app/macos/Runner/messages.g.m b/packages/pigeon/example/app/macos/Runner/messages.g.m index 3e3bc65265ae..ed7655039d25 100644 --- a/packages/pigeon/example/app/macos/Runner/messages.g.m +++ b/packages/pigeon/example/app/macos/Runner/messages.g.m @@ -12,6 +12,97 @@ @import Flutter; #endif +static BOOL __attribute__((unused)) FLTPigeonDeepEquals(id _Nullable a, id _Nullable b) { + if (a == b) { + return YES; + } + if (a == nil) { + return b == [NSNull null]; + } + if (b == nil) { + return a == [NSNull null]; + } + if ([a isKindOfClass:[NSNumber class]] && [b isKindOfClass:[NSNumber class]]) { + return + [a isEqual:b] || (isnan([(NSNumber *)a doubleValue]) && isnan([(NSNumber *)b doubleValue])); + } + if ([a isKindOfClass:[NSArray class]] && [b isKindOfClass:[NSArray class]]) { + NSArray *arrayA = (NSArray *)a; + NSArray *arrayB = (NSArray *)b; + if (arrayA.count != arrayB.count) { + return NO; + } + for (NSUInteger i = 0; i < arrayA.count; i++) { + if (!FLTPigeonDeepEquals(arrayA[i], arrayB[i])) { + return NO; + } + } + return YES; + } + if ([a isKindOfClass:[NSDictionary class]] && [b isKindOfClass:[NSDictionary class]]) { + NSDictionary *dictA = (NSDictionary *)a; + NSDictionary *dictB = (NSDictionary *)b; + if (dictA.count != dictB.count) { + return NO; + } + for (id keyA in dictA) { + id valueA = dictA[keyA]; + BOOL found = NO; + for (id keyB in dictB) { + if (FLTPigeonDeepEquals(keyA, keyB)) { + id valueB = dictB[keyB]; + if (FLTPigeonDeepEquals(valueA, valueB)) { + found = YES; + break; + } else { + return NO; + } + } + } + if (!found) { + return NO; + } + } + return YES; + } + return [a isEqual:b]; +} + +static NSUInteger __attribute__((unused)) FLTPigeonDeepHash(id _Nullable value) { + if (value == nil || value == (id)[NSNull null]) { + return 0; + } + if ([value isKindOfClass:[NSNumber class]]) { + NSNumber *n = (NSNumber *)value; + double d = n.doubleValue; + if (isnan(d)) { + // Normalize NaN to a consistent hash. + return (NSUInteger)0x7FF8000000000000; + } + if (d == 0.0) { + // Normalize -0.0 to 0.0 so they have the same hash code. + d = 0.0; + } + return @(d).hash; + } + if ([value isKindOfClass:[NSArray class]]) { + NSUInteger result = 1; + for (id item in (NSArray *)value) { + result = result * 31 + FLTPigeonDeepHash(item); + } + return result; + } + if ([value isKindOfClass:[NSDictionary class]]) { + NSUInteger result = 0; + NSDictionary *dict = (NSDictionary *)value; + for (id key in dict) { + result += ((FLTPigeonDeepHash(key) * 31) ^ FLTPigeonDeepHash(dict[key])); + } + return result; + } + return [value hash]; +} + static NSArray *wrapResult(id result, FlutterError *error) { if (error) { return @[ @@ -83,6 +174,27 @@ + (nullable PGNMessageData *)nullableFromList:(NSArray *)list { self.data ?: [NSNull null], ]; } +- (BOOL)isEqual:(id)object { + if (self == object) { + return YES; + } + if (![object isKindOfClass:[self class]]) { + return NO; + } + PGNMessageData *other = (PGNMessageData *)object; + return FLTPigeonDeepEquals(self.name, other.name) && + FLTPigeonDeepEquals(self.description, other.description) && self.code == other.code && + FLTPigeonDeepEquals(self.data, other.data); +} + +- (NSUInteger)hash { + NSUInteger result = [self class].hash; + result = result * 31 + FLTPigeonDeepHash(self.name); + result = result * 31 + FLTPigeonDeepHash(self.description); + result = result * 31 + @(self.code).hash; + result = result * 31 + FLTPigeonDeepHash(self.data); + return result; +} @end @interface PGNMessagesPigeonCodecReader : FlutterStandardReader diff --git a/packages/pigeon/example/app/windows/runner/messages.g.cpp b/packages/pigeon/example/app/windows/runner/messages.g.cpp index 755efbc8570b..11453da4e053 100644 --- a/packages/pigeon/example/app/windows/runner/messages.g.cpp +++ b/packages/pigeon/example/app/windows/runner/messages.g.cpp @@ -13,16 +13,18 @@ #include #include +#include +#include #include #include #include namespace pigeon_example { -using flutter::BasicMessageChannel; -using flutter::CustomEncodableValue; -using flutter::EncodableList; -using flutter::EncodableMap; -using flutter::EncodableValue; +using ::flutter::BasicMessageChannel; +using ::flutter::CustomEncodableValue; +using ::flutter::EncodableList; +using ::flutter::EncodableMap; +using ::flutter::EncodableValue; FlutterError CreateConnectionError(const std::string channel_name) { return FlutterError( @@ -31,6 +33,212 @@ FlutterError CreateConnectionError(const std::string channel_name) { EncodableValue("")); } +namespace { +template +bool PigeonInternalDeepEquals(const T& a, const T& b); + +bool PigeonInternalDeepEquals(const double& a, const double& b); + +template +bool PigeonInternalDeepEquals(const std::vector& a, const std::vector& b); + +template +bool PigeonInternalDeepEquals(const std::map& a, const std::map& b); + +template +bool PigeonInternalDeepEquals(const std::optional& a, + const std::optional& b); + +template +bool PigeonInternalDeepEquals(const std::unique_ptr& a, + const std::unique_ptr& b); + +bool PigeonInternalDeepEquals(const ::flutter::EncodableValue& a, + const ::flutter::EncodableValue& b); + +template +bool PigeonInternalDeepEquals(const T& a, const T& b) { + return a == b; +} + +template +bool PigeonInternalDeepEquals(const std::vector& a, + const std::vector& b) { + if (a.size() != b.size()) { + return false; + } + for (size_t i = 0; i < a.size(); ++i) { + if (!PigeonInternalDeepEquals(a[i], b[i])) { + return false; + } + } + return true; +} + +template +bool PigeonInternalDeepEquals(const std::map& a, + const std::map& b) { + if (a.size() != b.size()) { + return false; + } + for (const auto& kv : a) { + bool found = false; + for (const auto& b_kv : b) { + if (PigeonInternalDeepEquals(kv.first, b_kv.first)) { + if (PigeonInternalDeepEquals(kv.second, b_kv.second)) { + found = true; + break; + } else { + return false; + } + } + } + if (!found) { + return false; + } + } + return true; +} + +bool PigeonInternalDeepEquals(const double& a, const double& b) { + // Normalize -0.0 to 0.0 and handle NaN equality. + return (a == b) || (std::isnan(a) && std::isnan(b)); +} + +template +bool PigeonInternalDeepEquals(const std::optional& a, + const std::optional& b) { + if (!a && !b) { + return true; + } + if (!a || !b) { + return false; + } + return PigeonInternalDeepEquals(*a, *b); +} + +template +bool PigeonInternalDeepEquals(const std::unique_ptr& a, + const std::unique_ptr& b) { + if (a.get() == b.get()) { + return true; + } + if (!a || !b) { + return false; + } + return PigeonInternalDeepEquals(*a, *b); +} + +bool PigeonInternalDeepEquals(const ::flutter::EncodableValue& a, + const ::flutter::EncodableValue& b) { + if (a.index() != b.index()) { + return false; + } + if (const double* da = std::get_if(&a)) { + return PigeonInternalDeepEquals(*da, std::get(b)); + } else if (const ::flutter::EncodableList* la = + std::get_if<::flutter::EncodableList>(&a)) { + return PigeonInternalDeepEquals(*la, std::get<::flutter::EncodableList>(b)); + } else if (const ::flutter::EncodableMap* ma = + std::get_if<::flutter::EncodableMap>(&a)) { + return PigeonInternalDeepEquals(*ma, std::get<::flutter::EncodableMap>(b)); + } + return a == b; +} + +template +size_t PigeonInternalDeepHash(const T& v); + +size_t PigeonInternalDeepHash(const double& v); + +template +size_t PigeonInternalDeepHash(const std::vector& v); + +template +size_t PigeonInternalDeepHash(const std::map& v); + +template +size_t PigeonInternalDeepHash(const std::optional& v); + +template +size_t PigeonInternalDeepHash(const std::unique_ptr& v); + +size_t PigeonInternalDeepHash(const ::flutter::EncodableValue& v); + +template +size_t PigeonInternalDeepHash(const T& v) { + return std::hash()(v); +} + +template +size_t PigeonInternalDeepHash(const std::vector& v) { + size_t result = 1; + for (const auto& item : v) { + result = result * 31 + PigeonInternalDeepHash(item); + } + return result; +} + +template +size_t PigeonInternalDeepHash(const std::map& v) { + size_t result = 0; + for (const auto& kv : v) { + result += ((PigeonInternalDeepHash(kv.first) * 31) ^ + PigeonInternalDeepHash(kv.second)); + } + return result; +} + +size_t PigeonInternalDeepHash(const double& v) { + if (std::isnan(v)) { + // Normalize NaN to a consistent hash. + return std::hash()(std::numeric_limits::quiet_NaN()); + } + if (v == 0.0) { + // Normalize -0.0 to 0.0 so they have the same hash code. + return std::hash()(0.0); + } + return std::hash()(v); +} + +template +size_t PigeonInternalDeepHash(const std::optional& v) { + return v ? PigeonInternalDeepHash(*v) : 0; +} + +template +size_t PigeonInternalDeepHash(const std::unique_ptr& v) { + return v ? PigeonInternalDeepHash(*v) : 0; +} + +size_t PigeonInternalDeepHash(const ::flutter::EncodableValue& v) { + size_t result = v.index(); + if (const double* dv = std::get_if(&v)) { + result = result * 31 + PigeonInternalDeepHash(*dv); + } else if (const ::flutter::EncodableList* lv = + std::get_if<::flutter::EncodableList>(&v)) { + result = result * 31 + PigeonInternalDeepHash(*lv); + } else if (const ::flutter::EncodableMap* mv = + std::get_if<::flutter::EncodableMap>(&v)) { + result = result * 31 + PigeonInternalDeepHash(*mv); + } else { + std::visit( + [&result](const auto& val) { + using T = std::decay_t; + if constexpr (!std::is_same_v && + !std::is_same_v && + !std::is_same_v && + !std::is_same_v && + !std::is_same_v) { + result = result * 31 + PigeonInternalDeepHash(val); + } + }, + v); + } + return result; +} + +} // namespace // MessageData MessageData::MessageData(const Code& code, const EncodableMap& data) @@ -102,10 +310,32 @@ MessageData MessageData::FromEncodableList(const EncodableList& list) { return decoded; } +bool MessageData::operator==(const MessageData& other) const { + return PigeonInternalDeepEquals(name_, other.name_) && + PigeonInternalDeepEquals(description_, other.description_) && + PigeonInternalDeepEquals(code_, other.code_) && + PigeonInternalDeepEquals(data_, other.data_); +} + +bool MessageData::operator!=(const MessageData& other) const { + return !(*this == other); +} + +size_t MessageData::Hash() const { + size_t result = 1; + result = result * 31 + PigeonInternalDeepHash(name_); + result = result * 31 + PigeonInternalDeepHash(description_); + result = result * 31 + PigeonInternalDeepHash(code_); + result = result * 31 + PigeonInternalDeepHash(data_); + return result; +} + +size_t PigeonInternalDeepHash(const MessageData& v) { return v.Hash(); } + PigeonInternalCodecSerializer::PigeonInternalCodecSerializer() {} EncodableValue PigeonInternalCodecSerializer::ReadValueOfType( - uint8_t type, flutter::ByteStreamReader* stream) const { + uint8_t type, ::flutter::ByteStreamReader* stream) const { switch (type) { case 129: { const auto& encodable_enum_arg = ReadValue(stream); @@ -120,12 +350,12 @@ EncodableValue PigeonInternalCodecSerializer::ReadValueOfType( std::get(ReadValue(stream)))); } default: - return flutter::StandardCodecSerializer::ReadValueOfType(type, stream); + return ::flutter::StandardCodecSerializer::ReadValueOfType(type, stream); } } void PigeonInternalCodecSerializer::WriteValue( - const EncodableValue& value, flutter::ByteStreamWriter* stream) const { + const EncodableValue& value, ::flutter::ByteStreamWriter* stream) const { if (const CustomEncodableValue* custom_value = std::get_if(&value)) { if (custom_value->type() == typeid(Code)) { @@ -144,23 +374,23 @@ void PigeonInternalCodecSerializer::WriteValue( return; } } - flutter::StandardCodecSerializer::WriteValue(value, stream); + ::flutter::StandardCodecSerializer::WriteValue(value, stream); } /// The codec used by ExampleHostApi. -const flutter::StandardMessageCodec& ExampleHostApi::GetCodec() { - return flutter::StandardMessageCodec::GetInstance( +const ::flutter::StandardMessageCodec& ExampleHostApi::GetCodec() { + return ::flutter::StandardMessageCodec::GetInstance( &PigeonInternalCodecSerializer::GetInstance()); } // Sets up an instance of `ExampleHostApi` to handle messages through the // `binary_messenger`. -void ExampleHostApi::SetUp(flutter::BinaryMessenger* binary_messenger, +void ExampleHostApi::SetUp(::flutter::BinaryMessenger* binary_messenger, ExampleHostApi* api) { ExampleHostApi::SetUp(binary_messenger, api, ""); } -void ExampleHostApi::SetUp(flutter::BinaryMessenger* binary_messenger, +void ExampleHostApi::SetUp(::flutter::BinaryMessenger* binary_messenger, ExampleHostApi* api, const std::string& message_channel_suffix) { const std::string prepended_suffix = @@ -176,7 +406,7 @@ void ExampleHostApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { ErrorOr output = api->GetHostLanguage(); if (output.has_error()) { @@ -203,7 +433,7 @@ void ExampleHostApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_a_arg = args.at(0); @@ -243,7 +473,7 @@ void ExampleHostApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_message_arg = args.at(0); @@ -287,18 +517,20 @@ EncodableValue ExampleHostApi::WrapError(const FlutterError& error) { // Generated class from Pigeon that represents Flutter messages that can be // called from C++. -MessageFlutterApi::MessageFlutterApi(flutter::BinaryMessenger* binary_messenger) +MessageFlutterApi::MessageFlutterApi( + ::flutter::BinaryMessenger* binary_messenger) : binary_messenger_(binary_messenger), message_channel_suffix_("") {} -MessageFlutterApi::MessageFlutterApi(flutter::BinaryMessenger* binary_messenger, - const std::string& message_channel_suffix) +MessageFlutterApi::MessageFlutterApi( + ::flutter::BinaryMessenger* binary_messenger, + const std::string& message_channel_suffix) : binary_messenger_(binary_messenger), message_channel_suffix_(message_channel_suffix.length() > 0 ? std::string(".") + message_channel_suffix : "") {} -const flutter::StandardMessageCodec& MessageFlutterApi::GetCodec() { - return flutter::StandardMessageCodec::GetInstance( +const ::flutter::StandardMessageCodec& MessageFlutterApi::GetCodec() { + return ::flutter::StandardMessageCodec::GetInstance( &PigeonInternalCodecSerializer::GetInstance()); } diff --git a/packages/pigeon/example/app/windows/runner/messages.g.h b/packages/pigeon/example/app/windows/runner/messages.g.h index c56c0d1cf171..b23312baccff 100644 --- a/packages/pigeon/example/app/windows/runner/messages.g.h +++ b/packages/pigeon/example/app/windows/runner/messages.g.h @@ -25,17 +25,17 @@ class FlutterError { explicit FlutterError(const std::string& code, const std::string& message) : code_(code), message_(message) {} explicit FlutterError(const std::string& code, const std::string& message, - const flutter::EncodableValue& details) + const ::flutter::EncodableValue& details) : code_(code), message_(message), details_(details) {} const std::string& code() const { return code_; } const std::string& message() const { return message_; } - const flutter::EncodableValue& details() const { return details_; } + const ::flutter::EncodableValue& details() const { return details_; } private: std::string code_; std::string message_; - flutter::EncodableValue details_; + ::flutter::EncodableValue details_; }; template @@ -65,11 +65,11 @@ enum class Code { kOne = 0, kTwo = 1 }; class MessageData { public: // Constructs an object setting all non-nullable fields. - explicit MessageData(const Code& code, const flutter::EncodableMap& data); + explicit MessageData(const Code& code, const ::flutter::EncodableMap& data); // Constructs an object setting all fields. explicit MessageData(const std::string* name, const std::string* description, - const Code& code, const flutter::EncodableMap& data); + const Code& code, const ::flutter::EncodableMap& data); const std::string* name() const; void set_name(const std::string_view* value_arg); @@ -82,22 +82,29 @@ class MessageData { const Code& code() const; void set_code(const Code& value_arg); - const flutter::EncodableMap& data() const; - void set_data(const flutter::EncodableMap& value_arg); + const ::flutter::EncodableMap& data() const; + void set_data(const ::flutter::EncodableMap& value_arg); + + bool operator==(const MessageData& other) const; + bool operator!=(const MessageData& other) const; + /// Returns a hash code value for the object. This method is supported for the + /// benefit of hash tables. + size_t Hash() const; private: - static MessageData FromEncodableList(const flutter::EncodableList& list); - flutter::EncodableList ToEncodableList() const; + static MessageData FromEncodableList(const ::flutter::EncodableList& list); + ::flutter::EncodableList ToEncodableList() const; friend class ExampleHostApi; friend class MessageFlutterApi; friend class PigeonInternalCodecSerializer; std::optional name_; std::optional description_; Code code_; - flutter::EncodableMap data_; + ::flutter::EncodableMap data_; }; -class PigeonInternalCodecSerializer : public flutter::StandardCodecSerializer { +class PigeonInternalCodecSerializer + : public ::flutter::StandardCodecSerializer { public: PigeonInternalCodecSerializer(); inline static PigeonInternalCodecSerializer& GetInstance() { @@ -105,12 +112,12 @@ class PigeonInternalCodecSerializer : public flutter::StandardCodecSerializer { return sInstance; } - void WriteValue(const flutter::EncodableValue& value, - flutter::ByteStreamWriter* stream) const override; + void WriteValue(const ::flutter::EncodableValue& value, + ::flutter::ByteStreamWriter* stream) const override; protected: - flutter::EncodableValue ReadValueOfType( - uint8_t type, flutter::ByteStreamReader* stream) const override; + ::flutter::EncodableValue ReadValueOfType( + uint8_t type, ::flutter::ByteStreamReader* stream) const override; }; // Generated interface from Pigeon that represents a handler of messages from @@ -126,16 +133,16 @@ class ExampleHostApi { std::function reply)> result) = 0; // The codec used by ExampleHostApi. - static const flutter::StandardMessageCodec& GetCodec(); + static const ::flutter::StandardMessageCodec& GetCodec(); // Sets up an instance of `ExampleHostApi` to handle messages through the // `binary_messenger`. - static void SetUp(flutter::BinaryMessenger* binary_messenger, + static void SetUp(::flutter::BinaryMessenger* binary_messenger, ExampleHostApi* api); - static void SetUp(flutter::BinaryMessenger* binary_messenger, + static void SetUp(::flutter::BinaryMessenger* binary_messenger, ExampleHostApi* api, const std::string& message_channel_suffix); - static flutter::EncodableValue WrapError(std::string_view error_message); - static flutter::EncodableValue WrapError(const FlutterError& error); + static ::flutter::EncodableValue WrapError(std::string_view error_message); + static ::flutter::EncodableValue WrapError(const FlutterError& error); protected: ExampleHostApi() = default; @@ -144,16 +151,16 @@ class ExampleHostApi { // called from C++. class MessageFlutterApi { public: - MessageFlutterApi(flutter::BinaryMessenger* binary_messenger); - MessageFlutterApi(flutter::BinaryMessenger* binary_messenger, + MessageFlutterApi(::flutter::BinaryMessenger* binary_messenger); + MessageFlutterApi(::flutter::BinaryMessenger* binary_messenger, const std::string& message_channel_suffix); - static const flutter::StandardMessageCodec& GetCodec(); + static const ::flutter::StandardMessageCodec& GetCodec(); void FlutterMethod(const std::string* a_string, std::function&& on_success, std::function&& on_error); private: - flutter::BinaryMessenger* binary_messenger_; + ::flutter::BinaryMessenger* binary_messenger_; std::string message_channel_suffix_; }; diff --git a/packages/pigeon/lib/src/ast.dart b/packages/pigeon/lib/src/ast.dart index b51f66bb67ad..aba0e0891cae 100644 --- a/packages/pigeon/lib/src/ast.dart +++ b/packages/pigeon/lib/src/ast.dart @@ -496,13 +496,13 @@ class TypeDeclaration { associatedProxyApi = null, typeArguments = const []; - /// The base name of the [TypeDeclaration] (ex 'Foo' to 'Foo?'). + /// The base name of the [TypeDeclaration] (ex `Foo` to `Foo?`). final String baseName; /// Whether the declaration represents 'void'. bool get isVoid => baseName == 'void'; - /// Whether the type arguments to the entity (ex 'Bar' to 'Foo?'). + /// Whether the type arguments to the entity (ex `Bar` to `Foo?`). final List typeArguments; /// Whether the type is nullable. diff --git a/packages/pigeon/lib/src/cpp/cpp_generator.dart b/packages/pigeon/lib/src/cpp/cpp_generator.dart index 9708198f6cd8..ffaf56787d66 100644 --- a/packages/pigeon/lib/src/cpp/cpp_generator.dart +++ b/packages/pigeon/lib/src/cpp/cpp_generator.dart @@ -20,7 +20,7 @@ const DocumentCommentSpecification _docCommentSpec = DocumentCommentSpecification(_commentPrefix); /// The default serializer for Flutter. -const String _standardCodecSerializer = 'flutter::StandardCodecSerializer'; +const String _standardCodecSerializer = '::flutter::StandardCodecSerializer'; /// The name of the codec serializer. const String _codecSerializerName = '${classNamePrefix}CodecSerializer'; @@ -459,6 +459,30 @@ class CppHeaderGenerator extends StructuredGenerator { } indent.newln(); } + + _writeFunctionDeclaration( + indent, + 'operator==', + returnType: 'bool', + parameters: ['const ${classDefinition.name}& other'], + isConst: true, + ); + _writeFunctionDeclaration( + indent, + 'operator!=', + returnType: 'bool', + parameters: ['const ${classDefinition.name}& other'], + isConst: true, + ); + indent.writeln( + '/// Returns a hash code value for the object. This method is supported for the benefit of hash tables.', + ); + _writeFunctionDeclaration( + indent, + 'Hash', + returnType: 'size_t', + isConst: true, + ); }); _writeAccessBlock(indent, _ClassAccess.private, () { @@ -466,22 +490,22 @@ class CppHeaderGenerator extends StructuredGenerator { indent, 'FromEncodableList', returnType: isOverflowClass - ? 'flutter::EncodableValue' + ? '::flutter::EncodableValue' : classDefinition.name, - parameters: ['const flutter::EncodableList& list'], + parameters: ['const ::flutter::EncodableList& list'], isStatic: true, ); _writeFunctionDeclaration( indent, 'ToEncodableList', - returnType: 'flutter::EncodableList', + returnType: '::flutter::EncodableList', isConst: true, ); if (isOverflowClass) { _writeFunctionDeclaration( indent, 'Unwrap', - returnType: 'flutter::EncodableValue', + returnType: '::flutter::EncodableValue', ); } if (!isOverflowClass && root.requiresOverflowClass) { @@ -556,8 +580,8 @@ class CppHeaderGenerator extends StructuredGenerator { 'WriteValue', returnType: _voidType, parameters: [ - 'const flutter::EncodableValue& value', - 'flutter::ByteStreamWriter* stream', + 'const ::flutter::EncodableValue& value', + '::flutter::ByteStreamWriter* stream', ], isConst: true, isOverride: true, @@ -567,10 +591,10 @@ class CppHeaderGenerator extends StructuredGenerator { _writeFunctionDeclaration( indent, 'ReadValueOfType', - returnType: 'flutter::EncodableValue', + returnType: '::flutter::EncodableValue', parameters: [ 'uint8_t type', - 'flutter::ByteStreamReader* stream', + '::flutter::ByteStreamReader* stream', ], isConst: true, isOverride: true, @@ -603,20 +627,20 @@ class CppHeaderGenerator extends StructuredGenerator { _writeFunctionDeclaration( indent, api.name, - parameters: ['flutter::BinaryMessenger* binary_messenger'], + parameters: ['::flutter::BinaryMessenger* binary_messenger'], ); _writeFunctionDeclaration( indent, api.name, parameters: [ - 'flutter::BinaryMessenger* binary_messenger', + '::flutter::BinaryMessenger* binary_messenger', 'const std::string& message_channel_suffix', ], ); _writeFunctionDeclaration( indent, 'GetCodec', - returnType: 'const flutter::StandardMessageCodec&', + returnType: 'const ::flutter::StandardMessageCodec&', isStatic: true, ); for (final Method func in api.methods) { @@ -656,7 +680,7 @@ class CppHeaderGenerator extends StructuredGenerator { } }); indent.addScoped(' private:', null, () { - indent.writeln('flutter::BinaryMessenger* binary_messenger_;'); + indent.writeln('::flutter::BinaryMessenger* binary_messenger_;'); indent.writeln('std::string message_channel_suffix_;'); }); }, nestCount: 0); @@ -758,7 +782,7 @@ class CppHeaderGenerator extends StructuredGenerator { _writeFunctionDeclaration( indent, 'GetCodec', - returnType: 'const flutter::StandardMessageCodec&', + returnType: 'const ::flutter::StandardMessageCodec&', isStatic: true, ); indent.writeln( @@ -770,7 +794,7 @@ class CppHeaderGenerator extends StructuredGenerator { returnType: _voidType, isStatic: true, parameters: [ - 'flutter::BinaryMessenger* binary_messenger', + '::flutter::BinaryMessenger* binary_messenger', '${api.name}* api', ], ); @@ -780,7 +804,7 @@ class CppHeaderGenerator extends StructuredGenerator { returnType: _voidType, isStatic: true, parameters: [ - 'flutter::BinaryMessenger* binary_messenger', + '::flutter::BinaryMessenger* binary_messenger', '${api.name}* api', 'const std::string& message_channel_suffix', ], @@ -788,14 +812,14 @@ class CppHeaderGenerator extends StructuredGenerator { _writeFunctionDeclaration( indent, 'WrapError', - returnType: 'flutter::EncodableValue', + returnType: '::flutter::EncodableValue', isStatic: true, parameters: ['std::string_view error_message'], ); _writeFunctionDeclaration( indent, 'WrapError', - returnType: 'flutter::EncodableValue', + returnType: '::flutter::EncodableValue', isStatic: true, parameters: ['const FlutterError& error'], ); @@ -839,17 +863,17 @@ class FlutterError { \t\t: code_(code) {} \texplicit FlutterError(const std::string& code, const std::string& message) \t\t: code_(code), message_(message) {} -\texplicit FlutterError(const std::string& code, const std::string& message, const flutter::EncodableValue& details) +\texplicit FlutterError(const std::string& code, const std::string& message, const ::flutter::EncodableValue& details) \t\t: code_(code), message_(message), details_(details) {} \tconst std::string& code() const { return code_; } \tconst std::string& message() const { return message_; } -\tconst flutter::EncodableValue& details() const { return details_; } +\tconst ::flutter::EncodableValue& details() const { return details_; } private: \tstd::string code_; \tstd::string message_; -\tflutter::EncodableValue details_; +\t::flutter::EncodableValue details_; };'''); } @@ -937,6 +961,8 @@ class CppSourceGenerator extends StructuredGenerator { ]); indent.newln(); _writeSystemHeaderIncludeBlock(indent, [ + 'cmath', + 'limits', 'map', 'string', 'optional', @@ -964,11 +990,11 @@ class CppSourceGenerator extends StructuredGenerator { required String dartPackageName, }) { final usingDirectives = [ - 'flutter::BasicMessageChannel', - 'flutter::CustomEncodableValue', - 'flutter::EncodableList', - 'flutter::EncodableMap', - 'flutter::EncodableValue', + '::flutter::BasicMessageChannel', + '::flutter::CustomEncodableValue', + '::flutter::EncodableList', + '::flutter::EncodableMap', + '::flutter::EncodableValue', ]; usingDirectives.sort(); for (final using in usingDirectives) { @@ -988,6 +1014,10 @@ class CppSourceGenerator extends StructuredGenerator { EncodableValue(""));'''); }, ); + indent.writeln('namespace {'); + _writeDeepEquals(indent); + _writeDeepHash(indent); + indent.writeln('} // namespace'); } @override @@ -1052,6 +1082,267 @@ class CppSourceGenerator extends StructuredGenerator { classDefinition, dartPackageName: dartPackageName, ); + + _writeFunctionDefinition( + indent, + 'operator==', + scope: classDefinition.name, + returnType: 'bool', + parameters: ['const ${classDefinition.name}& other'], + isConst: true, + body: () { + final Iterable checks = orderedFields.map((NamedType field) { + final String name = _makeInstanceVariableName(field); + return 'PigeonInternalDeepEquals($name, other.$name)'; + }); + if (checks.isEmpty) { + indent.writeln('return true;'); + } else { + indent.writeln('return ${checks.join(' && ')};'); + } + }, + ); + + _writeFunctionDefinition( + indent, + 'operator!=', + scope: classDefinition.name, + returnType: 'bool', + parameters: ['const ${classDefinition.name}& other'], + isConst: true, + body: () { + indent.writeln('return !(*this == other);'); + }, + ); + + _writeFunctionDefinition( + indent, + 'Hash', + scope: classDefinition.name, + returnType: 'size_t', + isConst: true, + body: () { + indent.writeln('size_t result = 1;'); + for (final field in orderedFields) { + final String name = _makeInstanceVariableName(field); + indent.writeln( + 'result = result * 31 + PigeonInternalDeepHash($name);', + ); + } + indent.writeln('return result;'); + }, + ); + + _writeFunctionDefinition( + indent, + 'PigeonInternalDeepHash', + returnType: 'size_t', + parameters: ['const ${classDefinition.name}& v'], + body: () { + indent.writeln('return v.Hash();'); + }, + ); + } + + void _writeDeepEquals(Indent indent) { + indent.format(''' +template +bool PigeonInternalDeepEquals(const T& a, const T& b); + +bool PigeonInternalDeepEquals(const double& a, const double& b); + +template +bool PigeonInternalDeepEquals(const std::vector& a, const std::vector& b); + +template +bool PigeonInternalDeepEquals(const std::map& a, const std::map& b); + +template +bool PigeonInternalDeepEquals(const std::optional& a, const std::optional& b); + +template +bool PigeonInternalDeepEquals(const std::unique_ptr& a, const std::unique_ptr& b); + +bool PigeonInternalDeepEquals(const ::flutter::EncodableValue& a, const ::flutter::EncodableValue& b); + +template +bool PigeonInternalDeepEquals(const T& a, const T& b) { + return a == b; +} + +template +bool PigeonInternalDeepEquals(const std::vector& a, const std::vector& b) { + if (a.size() != b.size()) { + return false; + } + for (size_t i = 0; i < a.size(); ++i) { + if (!PigeonInternalDeepEquals(a[i], b[i])) { + return false; + } + } + return true; +} + +template +bool PigeonInternalDeepEquals(const std::map& a, const std::map& b) { + if (a.size() != b.size()) { + return false; + } + for (const auto& kv : a) { + bool found = false; + for (const auto& b_kv : b) { + if (PigeonInternalDeepEquals(kv.first, b_kv.first)) { + if (PigeonInternalDeepEquals(kv.second, b_kv.second)) { + found = true; + break; + } else { + return false; + } + } + } + if (!found) { + return false; + } + } + return true; +} + +bool PigeonInternalDeepEquals(const double& a, const double& b) { + // Normalize -0.0 to 0.0 and handle NaN equality. + return (a == b) || (std::isnan(a) && std::isnan(b)); +} + +template +bool PigeonInternalDeepEquals(const std::optional& a, const std::optional& b) { + if (!a && !b) { + return true; + } + if (!a || !b) { + return false; + } + return PigeonInternalDeepEquals(*a, *b); +} + +template +bool PigeonInternalDeepEquals(const std::unique_ptr& a, const std::unique_ptr& b) { + if (a.get() == b.get()) { + return true; + } + if (!a || !b) { + return false; + } + return PigeonInternalDeepEquals(*a, *b); +} + +bool PigeonInternalDeepEquals(const ::flutter::EncodableValue& a, const ::flutter::EncodableValue& b) { + if (a.index() != b.index()) { + return false; + } + if (const double* da = std::get_if(&a)) { + return PigeonInternalDeepEquals(*da, std::get(b)); + } else if (const ::flutter::EncodableList* la = std::get_if<::flutter::EncodableList>(&a)) { + return PigeonInternalDeepEquals(*la, std::get<::flutter::EncodableList>(b)); + } else if (const ::flutter::EncodableMap* ma = std::get_if<::flutter::EncodableMap>(&a)) { + return PigeonInternalDeepEquals(*ma, std::get<::flutter::EncodableMap>(b)); + } + return a == b; +} +'''); + } + + void _writeDeepHash(Indent indent) { + indent.format(''' +template +size_t PigeonInternalDeepHash(const T& v); + +size_t PigeonInternalDeepHash(const double& v); + +template +size_t PigeonInternalDeepHash(const std::vector& v); + +template +size_t PigeonInternalDeepHash(const std::map& v); + +template +size_t PigeonInternalDeepHash(const std::optional& v); + +template +size_t PigeonInternalDeepHash(const std::unique_ptr& v); + +size_t PigeonInternalDeepHash(const ::flutter::EncodableValue& v); + +template +size_t PigeonInternalDeepHash(const T& v) { + return std::hash()(v); +} + +template +size_t PigeonInternalDeepHash(const std::vector& v) { + size_t result = 1; + for (const auto& item : v) { + result = result * 31 + PigeonInternalDeepHash(item); + } + return result; +} + +template +size_t PigeonInternalDeepHash(const std::map& v) { + size_t result = 0; + for (const auto& kv : v) { + result += ((PigeonInternalDeepHash(kv.first) * 31) ^ PigeonInternalDeepHash(kv.second)); + } + return result; +} + +size_t PigeonInternalDeepHash(const double& v) { + if (std::isnan(v)) { + // Normalize NaN to a consistent hash. + return std::hash()(std::numeric_limits::quiet_NaN()); + } + if (v == 0.0) { + // Normalize -0.0 to 0.0 so they have the same hash code. + return std::hash()(0.0); + } + return std::hash()(v); +} + +template +size_t PigeonInternalDeepHash(const std::optional& v) { + return v ? PigeonInternalDeepHash(*v) : 0; +} + +template +size_t PigeonInternalDeepHash(const std::unique_ptr& v) { + return v ? PigeonInternalDeepHash(*v) : 0; +} + +size_t PigeonInternalDeepHash(const ::flutter::EncodableValue& v) { + size_t result = v.index(); + if (const double* dv = std::get_if(&v)) { + result = result * 31 + PigeonInternalDeepHash(*dv); + } else if (const ::flutter::EncodableList* lv = + std::get_if<::flutter::EncodableList>(&v)) { + result = result * 31 + PigeonInternalDeepHash(*lv); + } else if (const ::flutter::EncodableMap* mv = + std::get_if<::flutter::EncodableMap>(&v)) { + result = result * 31 + PigeonInternalDeepHash(*mv); + } else { + std::visit( + [&result](const auto& val) { + using T = std::decay_t; + if constexpr (!std::is_same_v && + !std::is_same_v && + !std::is_same_v && + !std::is_same_v && + !std::is_same_v) { + result = result * 31 + PigeonInternalDeepHash(val); + } + }, + v); + } + return result; +} +'''); } @override @@ -1292,7 +1583,10 @@ EncodableValue $_overflowClassName::FromEncodableList( 'ReadValueOfType', scope: _codecSerializerName, returnType: 'EncodableValue', - parameters: ['uint8_t type', 'flutter::ByteStreamReader* stream'], + parameters: [ + 'uint8_t type', + '::flutter::ByteStreamReader* stream', + ], isConst: true, body: () { if (enumeratedTypes.isNotEmpty) { @@ -1330,7 +1624,7 @@ EncodableValue $_overflowClassName::FromEncodableList( returnType: _voidType, parameters: [ 'const EncodableValue& value', - 'flutter::ByteStreamWriter* stream', + '::flutter::ByteStreamWriter* stream', ], isConst: true, body: () { @@ -1388,7 +1682,7 @@ EncodableValue $_overflowClassName::FromEncodableList( indent, api.name, scope: api.name, - parameters: ['flutter::BinaryMessenger* binary_messenger'], + parameters: ['::flutter::BinaryMessenger* binary_messenger'], initializers: [ 'binary_messenger_(binary_messenger)', 'message_channel_suffix_("")', @@ -1399,7 +1693,7 @@ EncodableValue $_overflowClassName::FromEncodableList( api.name, scope: api.name, parameters: [ - 'flutter::BinaryMessenger* binary_messenger', + '::flutter::BinaryMessenger* binary_messenger', 'const std::string& message_channel_suffix', ], initializers: [ @@ -1411,10 +1705,10 @@ EncodableValue $_overflowClassName::FromEncodableList( indent, 'GetCodec', scope: api.name, - returnType: 'const flutter::StandardMessageCodec&', + returnType: 'const ::flutter::StandardMessageCodec&', body: () { indent.writeln( - 'return flutter::StandardMessageCodec::GetInstance(&$_codecSerializerName::GetInstance());', + 'return ::flutter::StandardMessageCodec::GetInstance(&$_codecSerializerName::GetInstance());', ); }, ); @@ -1545,10 +1839,10 @@ EncodableValue $_overflowClassName::FromEncodableList( indent, 'GetCodec', scope: api.name, - returnType: 'const flutter::StandardMessageCodec&', + returnType: 'const ::flutter::StandardMessageCodec&', body: () { indent.writeln( - 'return flutter::StandardMessageCodec::GetInstance(&$_codecSerializerName::GetInstance());', + 'return ::flutter::StandardMessageCodec::GetInstance(&$_codecSerializerName::GetInstance());', ); }, ); @@ -1561,7 +1855,7 @@ EncodableValue $_overflowClassName::FromEncodableList( scope: api.name, returnType: _voidType, parameters: [ - 'flutter::BinaryMessenger* binary_messenger', + '::flutter::BinaryMessenger* binary_messenger', '${api.name}* api', ], body: () { @@ -1574,7 +1868,7 @@ EncodableValue $_overflowClassName::FromEncodableList( scope: api.name, returnType: _voidType, parameters: [ - 'flutter::BinaryMessenger* binary_messenger', + '::flutter::BinaryMessenger* binary_messenger', '${api.name}* api', 'const std::string& message_channel_suffix', ], @@ -1595,7 +1889,7 @@ EncodableValue $_overflowClassName::FromEncodableList( ); indent.writeScoped('if (api != nullptr) {', '} else {', () { indent.write( - 'channel.SetMessageHandler([api](const EncodableValue& message, const flutter::MessageReply& reply) ', + 'channel.SetMessageHandler([api](const EncodableValue& message, const ::flutter::MessageReply& reply) ', ); indent.addScoped('{', '});', () { indent.writeScoped('try {', '}', () { @@ -2187,7 +2481,7 @@ String? _baseCppTypeForBuiltinDartType( TypeDeclaration type, { bool includeFlutterNamespace = true, }) { - final flutterNamespace = includeFlutterNamespace ? 'flutter::' : ''; + final flutterNamespace = includeFlutterNamespace ? '::flutter::' : ''; final cppTypeForDartTypeMap = { 'void': 'void', 'bool': 'bool', diff --git a/packages/pigeon/lib/src/dart/dart_generator.dart b/packages/pigeon/lib/src/dart/dart_generator.dart index 5ebf6dd01f2e..fb65af36f161 100644 --- a/packages/pigeon/lib/src/dart/dart_generator.dart +++ b/packages/pigeon/lib/src/dart/dart_generator.dart @@ -365,6 +365,9 @@ class DartGenerator extends StructuredGenerator { Class classDefinition, { required String dartPackageName, }) { + final Iterable fields = getFieldsInSerializationOrder( + classDefinition, + ); indent.writeln('@override'); indent.writeln('// ignore: avoid_equals_and_hash_code_on_mutable_classes'); indent.writeScoped('bool operator ==(Object other) {', '}', () { @@ -375,16 +378,28 @@ class DartGenerator extends StructuredGenerator { indent.writeln('return false;'); }, ); - indent.writeScoped('if (identical(this, other)) {', '}', () { + if (fields.isEmpty) { indent.writeln('return true;'); - }); - indent.writeln('return _deepEquals(encode(), other.encode());'); + } else { + indent.writeScoped('if (identical(this, other)) {', '}', () { + indent.writeln('return true;'); + }); + final String comparisons = fields + .map( + (NamedType field) => + '_deepEquals(${field.name}, other.${field.name})', + ) + .join(' && '); + indent.writeln('return $comparisons;'); + } }); + indent.newln(); indent.writeln('@override'); indent.writeln('// ignore: avoid_equals_and_hash_code_on_mutable_classes'); - indent.writeln('int get hashCode => Object.hashAll(_toList())'); - indent.addln(';'); + indent.writeln( + 'int get hashCode => _deepHash([runtimeType, ..._toList()]);', + ); } @override @@ -523,6 +538,7 @@ class DartGenerator extends StructuredGenerator { /// Writes the code for host [Api], [api]. /// Example: + /// ```dart /// class FooCodec extends StandardMessageCodec {...} /// /// abstract class Foo { @@ -530,6 +546,7 @@ class DartGenerator extends StructuredGenerator { /// int add(int x, int y); /// static void setUp(Foo api, {BinaryMessenger? binaryMessenger}) {...} /// } + /// ``` @override void writeFlutterApi( InternalDartOptions generatorOptions, @@ -599,6 +616,7 @@ class DartGenerator extends StructuredGenerator { /// Writes the code for host [Api], [api]. /// Example: + /// ```dart /// class FooCodec extends StandardMessageCodec {...} /// /// class Foo { @@ -606,6 +624,7 @@ class DartGenerator extends StructuredGenerator { /// static const MessageCodec codec = FooCodec(); /// Future add(int x, int y) async {...} /// } + /// ``` /// /// Messages will be sent and received in a list. /// @@ -1134,6 +1153,7 @@ final BinaryMessenger? ${varNamePrefix}binaryMessenger; } if (root.classes.isNotEmpty) { _writeDeepEquals(indent); + _writeDeepHash(indent); } if (root.containsProxyApi) { proxy_api_helper.writeProxyApiPigeonOverrides( @@ -1167,21 +1187,73 @@ final BinaryMessenger? ${varNamePrefix}binaryMessenger; void _writeDeepEquals(Indent indent) { indent.format(r''' bool _deepEquals(Object? a, Object? b) { + if (identical(a, b)) { + return true; + } + if (a is double && b is double) { + if (a.isNaN && b.isNaN) { + return true; + } + return a == b; + } if (a is List && b is List) { return a.length == b.length && a.indexed - .every(((int, dynamic) item) => _deepEquals(item.$2, b[item.$1])); + .every(((int, dynamic) item) => _deepEquals(item.$2, b[item.$1])); } if (a is Map && b is Map) { - return a.length == b.length && a.entries.every((MapEntry entry) => - (b as Map).containsKey(entry.key) && - _deepEquals(entry.value, b[entry.key])); + if (a.length != b.length) { + return false; + } + for (final MapEntry entryA in a.entries) { + bool found = false; + for (final MapEntry entryB in b.entries) { + if (_deepEquals(entryA.key, entryB.key)) { + if (_deepEquals(entryA.value, entryB.value)) { + found = true; + break; + } else { + return false; + } + } + } + if (!found) { + return false; + } + } + return true; } return a == b; } '''); } + void _writeDeepHash(Indent indent) { + indent.format(r''' +int _deepHash(Object? value) { + if (value is List) { + return Object.hashAll(value.map(_deepHash)); + } + if (value is Map) { + int result = 0; + for (final MapEntry entry in value.entries) { + result += (_deepHash(entry.key) * 31) ^ _deepHash(entry.value); + } + return result; + } + if (value is double && value.isNaN) { + // Normalize NaN to a consistent hash. + return 0x7FF8000000000000.hashCode; + } + if (value is double && value == 0.0) { + // Normalize -0.0 to 0.0 so they have the same hash code. + return 0.0.hashCode; + } + return value.hashCode; +} +'''); + } + static void _writeExtractReplyValueOrThrow(Indent indent) { indent.newln(); indent.format(''' diff --git a/packages/pigeon/lib/src/generator_tools.dart b/packages/pigeon/lib/src/generator_tools.dart index aadb022bd246..604691d46d3e 100644 --- a/packages/pigeon/lib/src/generator_tools.dart +++ b/packages/pigeon/lib/src/generator_tools.dart @@ -15,7 +15,7 @@ import 'generator.dart'; /// The current version of pigeon. /// /// This must match the version in pubspec.yaml. -const String pigeonVersion = '26.2.3'; +const String pigeonVersion = '26.3.3'; /// Default plugin package name. const String defaultPluginPackageName = 'dev.flutter.pigeon'; diff --git a/packages/pigeon/lib/src/gobject/gobject_generator.dart b/packages/pigeon/lib/src/gobject/gobject_generator.dart index 0daa9debd069..0906c005d78a 100644 --- a/packages/pigeon/lib/src/gobject/gobject_generator.dart +++ b/packages/pigeon/lib/src/gobject/gobject_generator.dart @@ -327,6 +327,31 @@ class GObjectHeaderGenerator '$returnType ${methodPrefix}_get_$fieldName(${getterArgs.join(', ')});', ); } + + indent.newln(); + addDocumentationComments(indent, [ + '${methodPrefix}_equals:', + '@a: a #$className.', + '@b: another #$className.', + '', + 'Checks if two #$className objects are equal.', + '', + 'Returns: TRUE if @a and @b are equal.', + ], _docCommentSpec); + indent.writeln( + 'gboolean ${methodPrefix}_equals($className* a, $className* b);', + ); + + indent.newln(); + addDocumentationComments(indent, [ + '${methodPrefix}_hash:', + '@object: a #$className.', + '', + 'Calculates a hash code for a #$className object.', + '', + 'Returns: the hash code.', + ], _docCommentSpec); + indent.writeln('guint ${methodPrefix}_hash($className* object);'); } @override @@ -818,7 +843,14 @@ class GObjectSourceGenerator required String dartPackageName, }) { indent.newln(); + indent.writeln('#include '); + indent.newln(); + indent.writeln('#include '); indent.writeln('#include "${generatorOptions.headerIncludePath}"'); + + _writeHashHelpers(indent); + _writeDeepEquals(indent); + _writeDeepHash(indent); } @override @@ -1039,6 +1071,281 @@ class GObjectSourceGenerator indent.writeln('return ${methodPrefix}_new(${args.join(', ')});'); }, ); + + _writeClassEquality( + generatorOptions, + root, + indent, + classDefinition, + dartPackageName: dartPackageName, + ); + } + + void _writeClassEquality( + InternalGObjectOptions generatorOptions, + Root root, + Indent indent, + Class classDefinition, { + required String dartPackageName, + }) { + final String module = _getModule(generatorOptions, dartPackageName); + final String snakeModule = _snakeCaseFromCamelCase(module); + final String className = _getClassName(module, classDefinition.name); + final String snakeClassName = _snakeCaseFromCamelCase(classDefinition.name); + + final String methodPrefix = _getMethodPrefix(module, classDefinition.name); + final String testMacro = '${snakeModule}_IS_$snakeClassName'.toUpperCase(); + + indent.newln(); + indent.writeScoped('gboolean ${methodPrefix}_equals($className* a, $className* b) {', '}', () { + indent.writeScoped('if (a == b) {', '}', () { + indent.writeln('return TRUE;'); + }); + indent.writeScoped('if (a == nullptr || b == nullptr) {', '}', () { + indent.writeln('return FALSE;'); + }); + for (final NamedType field in classDefinition.fields) { + final String fieldName = _getFieldName(field.name); + if (field.type.isClass) { + final String fieldMethodPrefix = _getMethodPrefix( + module, + field.type.baseName, + ); + indent.writeScoped( + 'if (!${fieldMethodPrefix}_equals(a->$fieldName, b->$fieldName)) {', + '}', + () { + indent.writeln('return FALSE;'); + }, + ); + } else if (field.type.isEnum) { + if (field.type.isNullable) { + indent.writeScoped( + 'if ((a->$fieldName == nullptr) != (b->$fieldName == nullptr)) {', + '}', + () { + indent.writeln('return FALSE;'); + }, + ); + indent.writeScoped( + 'if (a->$fieldName != nullptr && *a->$fieldName != *b->$fieldName) {', + '}', + () { + indent.writeln('return FALSE;'); + }, + ); + } else { + indent.writeScoped( + 'if (a->$fieldName != b->$fieldName) {', + '}', + () { + indent.writeln('return FALSE;'); + }, + ); + } + } else if (_isNumericListType(field.type)) { + indent.writeScoped('if (a->$fieldName != b->$fieldName) {', '}', () { + indent.writeScoped( + 'if (a->$fieldName == nullptr || b->$fieldName == nullptr) {', + '}', + () { + indent.writeln('return FALSE;'); + }, + ); + indent.writeScoped( + 'if (a->${fieldName}_length != b->${fieldName}_length) {', + '}', + () { + indent.writeln('return FALSE;'); + }, + ); + if (field.type.baseName == 'Float32List' || + field.type.baseName == 'Float64List') { + indent.writeScoped( + 'for (size_t i = 0; i < a->${fieldName}_length; i++) {', + '}', + () { + indent.writeScoped( + 'if (!flpigeon_equals_double(a->$fieldName[i], b->$fieldName[i])) {', + '}', + () { + indent.writeln('return FALSE;'); + }, + ); + }, + ); + } else { + final elementSize = field.type.baseName == 'Uint8List' + ? 'sizeof(uint8_t)' + : field.type.baseName == 'Int32List' + ? 'sizeof(int32_t)' + : 'sizeof(int64_t)'; + indent.writeScoped( + 'if (memcmp(a->$fieldName, b->$fieldName, a->${fieldName}_length * $elementSize) != 0) {', + '}', + () { + indent.writeln('return FALSE;'); + }, + ); + } + }); + } else if (field.type.baseName == 'bool' || + field.type.baseName == 'int') { + if (field.type.isNullable) { + indent.writeScoped( + 'if ((a->$fieldName == nullptr) != (b->$fieldName == nullptr)) {', + '}', + () { + indent.writeln('return FALSE;'); + }, + ); + indent.writeScoped( + 'if (a->$fieldName != nullptr && *a->$fieldName != *b->$fieldName) {', + '}', + () { + indent.writeln('return FALSE;'); + }, + ); + } else { + indent.writeScoped( + 'if (a->$fieldName != b->$fieldName) {', + '}', + () { + indent.writeln('return FALSE;'); + }, + ); + } + } else if (field.type.baseName == 'double') { + if (field.type.isNullable) { + indent.writeScoped( + 'if ((a->$fieldName == nullptr) != (b->$fieldName == nullptr)) {', + '}', + () { + indent.writeln('return FALSE;'); + }, + ); + indent.writeScoped( + 'if (a->$fieldName != nullptr && !flpigeon_equals_double(*a->$fieldName, *b->$fieldName)) {', + '}', + () { + indent.writeln('return FALSE;'); + }, + ); + } else { + indent.writeScoped( + 'if (!flpigeon_equals_double(a->$fieldName, b->$fieldName)) {', + '}', + () { + indent.writeln('return FALSE;'); + }, + ); + } + } else if (field.type.baseName == 'String') { + indent.writeScoped( + 'if (g_strcmp0(a->$fieldName, b->$fieldName) != 0) {', + '}', + () { + indent.writeln('return FALSE;'); + }, + ); + } else { + indent.writeScoped( + 'if (!flpigeon_deep_equals(a->$fieldName, b->$fieldName)) {', + '}', + () { + indent.writeln('return FALSE;'); + }, + ); + } + } + indent.writeln('return TRUE;'); + }); + + indent.newln(); + indent.writeScoped('guint ${methodPrefix}_hash($className* self) {', '}', () { + indent.writeln('g_return_val_if_fail($testMacro(self), 0);'); + indent.writeln('guint result = 0;'); + for (final NamedType field in classDefinition.fields) { + final String fieldName = _getFieldName(field.name); + if (field.type.isClass) { + final String fieldMethodPrefix = _getMethodPrefix( + module, + field.type.baseName, + ); + indent.writeln( + 'result = result * 31 + ${fieldMethodPrefix}_hash(self->$fieldName);', + ); + } else if (field.type.isEnum) { + if (field.type.isNullable) { + indent.writeln( + 'result = result * 31 + (self->$fieldName != nullptr ? static_cast(*self->$fieldName) : 0);', + ); + } else { + indent.writeln( + 'result = result * 31 + static_cast(self->$fieldName);', + ); + } + } else if (_isNumericListType(field.type)) { + indent.writeScoped('{', '}', () { + indent.writeln('size_t len = self->${fieldName}_length;'); + final String elementTypeName = _getType( + module, + field.type, + isElementType: true, + ); + indent.writeln('const $elementTypeName* data = self->$fieldName;'); + indent.writeScoped('if (data != nullptr) {', '}', () { + indent.writeScoped('for (size_t i = 0; i < len; i++) {', '}', () { + if (field.type.baseName == 'Int64List') { + indent.writeln( + 'result = result * 31 + static_cast(data[i] ^ (data[i] >> 32));', + ); + } else if (field.type.baseName == 'Float32List' || + field.type.baseName == 'Float64List') { + indent.writeln( + 'result = result * 31 + flpigeon_hash_double(data[i]);', + ); + } else { + indent.writeln( + 'result = result * 31 + static_cast(data[i]);', + ); + } + }); + }); + }); + } else if (field.type.baseName == 'bool' || + field.type.baseName == 'int') { + if (field.type.isNullable) { + indent.writeln( + 'result = result * 31 + (self->$fieldName != nullptr ? static_cast(*self->$fieldName) : 0);', + ); + } else { + indent.writeln( + 'result = result * 31 + static_cast(self->$fieldName);', + ); + } + } else if (field.type.baseName == 'double') { + if (field.type.isNullable) { + indent.writeln( + 'result = result * 31 + (self->$fieldName != nullptr ? flpigeon_hash_double(*self->$fieldName) : 0);', + ); + } else { + indent.writeln( + 'result = result * 31 + flpigeon_hash_double(self->$fieldName);', + ); + } + } else if (field.type.baseName == 'String') { + indent.writeln( + 'result = result * 31 + (self->$fieldName != nullptr ? g_str_hash(self->$fieldName) : 0);', + ); + } else { + indent.writeln( + 'result = result * 31 + flpigeon_deep_hash(self->$fieldName);', + ); + } + } + indent.writeln('return result;'); + }); } @override @@ -2254,6 +2561,7 @@ String _getType( TypeDeclaration type, { bool isOutput = false, bool primitive = false, + bool isElementType = false, }) { if (type.isClass) { return '${_getClassName(module, type.baseName)}*'; @@ -2273,14 +2581,29 @@ String _getType( } else if (type.baseName == 'String') { return isOutput ? 'gchar*' : 'const gchar*'; } else if (type.baseName == 'Uint8List') { + if (isElementType) { + return 'uint8_t'; + } return isOutput ? 'uint8_t*' : 'const uint8_t*'; } else if (type.baseName == 'Int32List') { + if (isElementType) { + return 'int32_t'; + } return isOutput ? 'int32_t*' : 'const int32_t*'; } else if (type.baseName == 'Int64List') { + if (isElementType) { + return 'int64_t'; + } return isOutput ? 'int64_t*' : 'const int64_t*'; } else if (type.baseName == 'Float32List') { + if (isElementType) { + return 'float'; + } return isOutput ? 'float*' : 'const float*'; } else if (type.baseName == 'Float64List') { + if (isElementType) { + return 'double'; + } return isOutput ? 'double*' : 'const double*'; } else { throw Exception('Unknown type ${type.baseName}'); @@ -2498,7 +2821,8 @@ String _fromFlValue(String module, TypeDeclaration type, String variableName) { } else if (type.baseName == 'Int64List') { return 'fl_value_get_int64_list($variableName)'; } else if (type.baseName == 'Float32List') { - return 'fl_value_get_float32_list($variableName)'; + // TODO(stuartmorgan): Support Float32List. + return 'nullptr'; } else if (type.baseName == 'Float64List') { return 'fl_value_get_float_list($variableName)'; } else { @@ -2512,3 +2836,263 @@ String _getResponseName(String name, String methodName) { methodName[0].toUpperCase() + methodName.substring(1); return '$name${upperMethodName}Response'; } + +void _writeHashHelpers(Indent indent) { + indent.writeScoped( + 'static guint G_GNUC_UNUSED flpigeon_hash_double(double v) {', + '}', + () { + indent.writeScoped('if (std::isnan(v)) {', '}', () { + indent.writeln('return static_cast(0x7FF80000);'); + }); + indent.writeScoped('if (v == 0.0) {', '}', () { + indent.writeln('v = 0.0;'); + }); + indent.writeln('union { double d; uint64_t u; } u;'); + indent.writeln('u.d = v;'); + indent.writeln('return static_cast(u.u ^ (u.u >> 32));'); + }, + ); + indent.writeScoped( + 'static gboolean G_GNUC_UNUSED flpigeon_equals_double(double a, double b) {', + '}', + () { + indent.writeln('return (a == b) || (std::isnan(a) && std::isnan(b));'); + }, + ); +} + +void _writeDeepEquals(Indent indent) { + indent.writeScoped( + 'static gboolean G_GNUC_UNUSED flpigeon_deep_equals(FlValue* a, FlValue* b) {', + '}', + () { + indent.writeScoped('if (a == b) {', '}', () { + indent.writeln('return TRUE;'); + }); + indent.writeScoped('if (a == nullptr || b == nullptr) {', '}', () { + indent.writeln('return FALSE;'); + }); + indent.writeScoped( + 'if (fl_value_get_type(a) != fl_value_get_type(b)) {', + '}', + () { + indent.writeln('return FALSE;'); + }, + ); + indent.writeScoped('switch (fl_value_get_type(a)) {', '}', () { + indent.writeln('case FL_VALUE_TYPE_NULL:'); + indent.writeln(' return TRUE;'); + indent.writeln('case FL_VALUE_TYPE_BOOL:'); + indent.writeln( + ' return fl_value_get_bool(a) == fl_value_get_bool(b);', + ); + indent.writeln('case FL_VALUE_TYPE_INT:'); + indent.writeln(' return fl_value_get_int(a) == fl_value_get_int(b);'); + indent.writeln('case FL_VALUE_TYPE_FLOAT: {'); + indent.writeln( + ' return flpigeon_equals_double(fl_value_get_float(a), fl_value_get_float(b));', + ); + indent.writeln('}'); + indent.writeln('case FL_VALUE_TYPE_STRING:'); + indent.writeln( + ' return g_strcmp0(fl_value_get_string(a), fl_value_get_string(b)) == 0;', + ); + indent.writeln('case FL_VALUE_TYPE_UINT8_LIST:'); + indent.writeln( + ' return fl_value_get_length(a) == fl_value_get_length(b) &&', + ); + indent.writeln( + ' memcmp(fl_value_get_uint8_list(a), fl_value_get_uint8_list(b), fl_value_get_length(a)) == 0;', + ); + indent.writeln('case FL_VALUE_TYPE_INT32_LIST:'); + indent.writeln( + ' return fl_value_get_length(a) == fl_value_get_length(b) &&', + ); + indent.writeln( + ' memcmp(fl_value_get_int32_list(a), fl_value_get_int32_list(b), fl_value_get_length(a) * sizeof(int32_t)) == 0;', + ); + indent.writeln('case FL_VALUE_TYPE_INT64_LIST:'); + indent.writeln( + ' return fl_value_get_length(a) == fl_value_get_length(b) &&', + ); + indent.writeln( + ' memcmp(fl_value_get_int64_list(a), fl_value_get_int64_list(b), fl_value_get_length(a) * sizeof(int64_t)) == 0;', + ); + indent.writeln('case FL_VALUE_TYPE_FLOAT_LIST: {'); + indent.writeln(' size_t len = fl_value_get_length(a);'); + indent.writeln(' if (len != fl_value_get_length(b)) {'); + indent.writeln(' return FALSE;'); + indent.writeln(' }'); + indent.writeln(' const double* a_data = fl_value_get_float_list(a);'); + indent.writeln(' const double* b_data = fl_value_get_float_list(b);'); + indent.writeScoped(' for (size_t i = 0; i < len; i++) {', '}', () { + indent.writeln( + 'if (!flpigeon_equals_double(a_data[i], b_data[i])) {', + ); + indent.writeln(' return FALSE;'); + indent.writeln('}'); + }); + indent.writeln(' return TRUE;'); + indent.writeln('}'); + indent.writeln('case FL_VALUE_TYPE_LIST: {'); + indent.writeln(' size_t len = fl_value_get_length(a);'); + indent.writeln(' if (len != fl_value_get_length(b)) {'); + indent.writeln(' return FALSE;'); + indent.writeln(' }'); + indent.writeScoped(' for (size_t i = 0; i < len; i++) {', '}', () { + indent.writeln( + 'if (!flpigeon_deep_equals(fl_value_get_list_value(a, i), fl_value_get_list_value(b, i))) {', + ); + indent.writeln(' return FALSE;'); + indent.writeln('}'); + }); + indent.writeln(' return TRUE;'); + indent.writeln('}'); + indent.writeln('case FL_VALUE_TYPE_MAP: {'); + indent.writeln(' size_t len = fl_value_get_length(a);'); + indent.writeln(' if (len != fl_value_get_length(b)) {'); + indent.writeln(' return FALSE;'); + indent.writeln(' }'); + indent.writeScoped(' for (size_t i = 0; i < len; i++) {', '}', () { + indent.writeln('FlValue* key = fl_value_get_map_key(a, i);'); + indent.writeln('FlValue* val = fl_value_get_map_value(a, i);'); + indent.writeln('gboolean found = FALSE;'); + indent.writeScoped('for (size_t j = 0; j < len; j++) {', '}', () { + indent.writeln('FlValue* b_key = fl_value_get_map_key(b, j);'); + indent.writeScoped( + 'if (flpigeon_deep_equals(key, b_key)) {', + '}', + () { + indent.writeln( + 'FlValue* b_val = fl_value_get_map_value(b, j);', + ); + indent.writeln('if (flpigeon_deep_equals(val, b_val)) {'); + indent.nest(1, () { + indent.writeln('found = TRUE;'); + indent.writeln('break;'); + }); + indent.writeln('} else {'); + indent.nest(1, () { + indent.writeln('return FALSE;'); + }); + indent.writeln('}'); + }, + ); + }); + indent.writeln('if (!found) {'); + indent.writeln(' return FALSE;'); + indent.writeln('}'); + }); + indent.writeln(' return TRUE;'); + indent.writeln('}'); + indent.writeln('default:'); + indent.writeln(' return FALSE;'); + }); + indent.writeln('return FALSE;'); + }, + ); +} + +void _writeDeepHash(Indent indent) { + indent.writeScoped( + 'static guint G_GNUC_UNUSED flpigeon_deep_hash(FlValue* value) {', + '}', + () { + indent.writeScoped('if (value == nullptr) {', '}', () { + indent.writeln('return 0;'); + }); + indent.writeScoped('switch (fl_value_get_type(value)) {', '}', () { + indent.writeln('case FL_VALUE_TYPE_NULL:'); + indent.writeln(' return 0;'); + indent.writeln('case FL_VALUE_TYPE_BOOL:'); + indent.writeln(' return fl_value_get_bool(value) ? 1231 : 1237;'); + indent.writeln('case FL_VALUE_TYPE_INT: {'); + indent.writeln(' int64_t v = fl_value_get_int(value);'); + indent.writeln(' return static_cast(v ^ (v >> 32));'); + indent.writeln('}'); + indent.writeln('case FL_VALUE_TYPE_FLOAT:'); + indent.writeln( + ' return flpigeon_hash_double(fl_value_get_float(value));', + ); + indent.writeln('case FL_VALUE_TYPE_STRING:'); + indent.writeln(' return g_str_hash(fl_value_get_string(value));'); + indent.writeln('case FL_VALUE_TYPE_UINT8_LIST: {'); + indent.writeln(' guint result = 1;'); + indent.writeln(' size_t len = fl_value_get_length(value);'); + indent.writeln( + ' const uint8_t* data = fl_value_get_uint8_list(value);', + ); + indent.writeScoped(' for (size_t i = 0; i < len; i++) {', ' }', () { + indent.writeln(' result = result * 31 + data[i];'); + }); + indent.writeln(' return result;'); + indent.writeln('}'); + indent.writeln('case FL_VALUE_TYPE_INT32_LIST: {'); + indent.writeln(' guint result = 1;'); + indent.writeln(' size_t len = fl_value_get_length(value);'); + indent.writeln( + ' const int32_t* data = fl_value_get_int32_list(value);', + ); + indent.writeScoped(' for (size_t i = 0; i < len; i++) {', ' }', () { + indent.writeln( + ' result = result * 31 + static_cast(data[i]);', + ); + }); + indent.writeln(' return result;'); + indent.writeln('}'); + indent.writeln('case FL_VALUE_TYPE_INT64_LIST: {'); + indent.writeln(' guint result = 1;'); + indent.writeln(' size_t len = fl_value_get_length(value);'); + indent.writeln( + ' const int64_t* data = fl_value_get_int64_list(value);', + ); + indent.writeScoped(' for (size_t i = 0; i < len; i++) {', ' }', () { + indent.writeln( + ' result = result * 31 + static_cast(data[i] ^ (data[i] >> 32));', + ); + }); + indent.writeln(' return result;'); + indent.writeln('}'); + indent.writeln('case FL_VALUE_TYPE_FLOAT_LIST: {'); + indent.writeln(' guint result = 1;'); + indent.writeln(' size_t len = fl_value_get_length(value);'); + indent.writeln( + ' const double* data = fl_value_get_float_list(value);', + ); + indent.writeScoped(' for (size_t i = 0; i < len; i++) {', '}', () { + indent.writeln( + 'result = result * 31 + flpigeon_hash_double(data[i]);', + ); + }); + indent.writeln(' return result;'); + indent.writeln('}'); + indent.writeln('case FL_VALUE_TYPE_LIST: {'); + indent.writeln(' guint result = 1;'); + indent.writeln(' size_t len = fl_value_get_length(value);'); + indent.writeScoped(' for (size_t i = 0; i < len; i++) {', '}', () { + indent.writeln( + 'result = result * 31 + flpigeon_deep_hash(fl_value_get_list_value(value, i));', + ); + }); + indent.writeln(' return result;'); + indent.writeln('}'); + indent.writeln('case FL_VALUE_TYPE_MAP: {'); + indent.writeln(' guint result = 0;'); + indent.writeln(' size_t len = fl_value_get_length(value);'); + indent.writeScoped(' for (size_t i = 0; i < len; i++) {', '}', () { + indent.writeln( + 'result += ((flpigeon_deep_hash(fl_value_get_map_key(value, i)) * 31) ^ flpigeon_deep_hash(fl_value_get_map_value(value, i)));', + ); + }); + indent.writeln(' return result;'); + indent.writeln('}'); + indent.writeln('default:'); + indent.writeln( + ' return static_cast(fl_value_get_type(value));', + ); + }); + indent.writeln('return 0;'); + }, + ); +} diff --git a/packages/pigeon/lib/src/java/java_generator.dart b/packages/pigeon/lib/src/java/java_generator.dart index af6181e91d2c..4b7f792dc1c3 100644 --- a/packages/pigeon/lib/src/java/java_generator.dart +++ b/packages/pigeon/lib/src/java/java_generator.dart @@ -208,6 +208,9 @@ class JavaGenerator extends StructuredGenerator { } indent.writeln('public class ${generatorOptions.className!} {'); indent.inc(); + _writeNumberHelpers(indent); + _writeDeepEquals(indent); + _writeDeepHashCode(indent); } @override @@ -383,13 +386,7 @@ class JavaGenerator extends StructuredGenerator { final Iterable checks = classDefinition.fields.map(( NamedType field, ) { - // Objects.equals only does pointer equality for array types. - if (_javaTypeIsArray(field.type)) { - return 'Arrays.equals(${field.name}, that.${field.name})'; - } - return field.type.isNullable - ? 'Objects.equals(${field.name}, that.${field.name})' - : '${field.name}.equals(that.${field.name})'; + return 'pigeonDeepEquals(${field.name}, that.${field.name})'; }); indent.writeln('return ${checks.join(' && ')};'); }); @@ -398,36 +395,273 @@ class JavaGenerator extends StructuredGenerator { // Implement hashCode(). indent.writeln('@Override'); indent.writeScoped('public int hashCode() {', '}', () { - // As with equalty checks, arrays need special handling. - final Iterable arrayFieldNames = classDefinition.fields - .where((NamedType field) => _javaTypeIsArray(field.type)) - .map((NamedType field) => field.name); - final Iterable nonArrayFieldNames = classDefinition.fields - .where((NamedType field) => !_javaTypeIsArray(field.type)) - .map((NamedType field) => field.name); - final nonArrayHashValue = nonArrayFieldNames.isNotEmpty - ? 'Objects.hash(${nonArrayFieldNames.join(', ')})' - : '0'; - - if (arrayFieldNames.isEmpty) { - // Return directly if there are no array variables, to avoid redundant - // variable lint warnings. - indent.writeln('return $nonArrayHashValue;'); + final Iterable fieldNames = classDefinition.fields.map( + (NamedType field) => field.name, + ); + if (fieldNames.isEmpty) { + indent.writeln('return Objects.hash(getClass());'); } else { - const resultVar = '${varNamePrefix}result'; - indent.writeln('int $resultVar = $nonArrayHashValue;'); - // Manually mix in the Arrays.hashCode values. - for (final name in arrayFieldNames) { - indent.writeln( - '$resultVar = 31 * $resultVar + Arrays.hashCode($name);', - ); - } - indent.writeln('return $resultVar;'); + indent.writeln( + 'Object[] fields = new Object[] {getClass(), ${fieldNames.join(', ')}};', + ); + indent.writeln('return pigeonDeepHashCode(fields);'); } }); indent.newln(); } + void _writeDeepEquals(Indent indent) { + indent.writeScoped( + 'static boolean pigeonDeepEquals(Object a, Object b) {', + '}', + () { + indent.writeln('if (a == b) { return true; }'); + indent.writeln('if (a == null || b == null) { return false; }'); + indent.writeScoped( + 'if (a instanceof byte[] && b instanceof byte[]) {', + '}', + () { + indent.writeln('return Arrays.equals((byte[]) a, (byte[]) b);'); + }, + ); + indent.writeScoped( + 'if (a instanceof int[] && b instanceof int[]) {', + '}', + () { + indent.writeln('return Arrays.equals((int[]) a, (int[]) b);'); + }, + ); + indent.writeScoped( + 'if (a instanceof long[] && b instanceof long[]) {', + '}', + () { + indent.writeln('return Arrays.equals((long[]) a, (long[]) b);'); + }, + ); + indent.writeScoped( + 'if (a instanceof double[] && b instanceof double[]) {', + '}', + () { + indent.writeln('double[] da = (double[]) a;'); + indent.writeln('double[] db = (double[]) b;'); + indent.writeScoped('if (da.length != db.length) {', '}', () { + indent.writeln('return false;'); + }); + indent.writeScoped( + 'for (int i = 0; i < da.length; i++) {', + '}', + () { + indent.writeScoped( + 'if (!pigeonDoubleEquals(da[i], db[i])) {', + '}', + () { + indent.writeln('return false;'); + }, + ); + }, + ); + indent.writeln('return true;'); + }, + ); + indent.writeScoped( + 'if (a instanceof List && b instanceof List) {', + '}', + () { + indent.writeln('List listA = (List) a;'); + indent.writeln('List listB = (List) b;'); + indent.writeln( + 'if (listA.size() != listB.size()) { return false; }', + ); + indent.writeScoped( + 'for (int i = 0; i < listA.size(); i++) {', + '}', + () { + indent.writeScoped( + 'if (!pigeonDeepEquals(listA.get(i), listB.get(i))) {', + '}', + () { + indent.writeln('return false;'); + }, + ); + }, + ); + indent.writeln('return true;'); + }, + ); + indent.writeScoped( + 'if (a instanceof Map && b instanceof Map) {', + '}', + () { + indent.writeln('Map mapA = (Map) a;'); + indent.writeln('Map mapB = (Map) b;'); + indent.writeln('if (mapA.size() != mapB.size()) { return false; }'); + indent.writeScoped( + 'for (Map.Entry entryA : mapA.entrySet()) {', + '}', + () { + indent.writeln('Object keyA = entryA.getKey();'); + indent.writeln('Object valueA = entryA.getValue();'); + indent.writeln('boolean found = false;'); + indent.writeScoped( + 'for (Map.Entry entryB : mapB.entrySet()) {', + '}', + () { + indent.writeln('Object keyB = entryB.getKey();'); + indent.writeScoped( + 'if (pigeonDeepEquals(keyA, keyB)) {', + '}', + () { + indent.writeln('Object valueB = entryB.getValue();'); + indent.writeln( + 'if (pigeonDeepEquals(valueA, valueB)) {', + ); + indent.nest(1, () { + indent.writeln('found = true;'); + indent.writeln('break;'); + }); + indent.writeln('} else {'); + indent.nest(1, () { + indent.writeln('return false;'); + }); + indent.writeln('}'); + }, + ); + }, + ); + indent.writeScoped('if (!found) {', '}', () { + indent.writeln('return false;'); + }); + }, + ); + indent.writeln('return true;'); + }, + ); + indent.writeScoped( + 'if (a instanceof Double && b instanceof Double) {', + '}', + () { + indent.writeln( + 'return pigeonDoubleEquals((double) a, (double) b);', + ); + }, + ); + indent.writeScoped( + 'if (a instanceof Float && b instanceof Float) {', + '}', + () { + indent.writeln('return pigeonFloatEquals((float) a, (float) b);'); + }, + ); + indent.writeln('return a.equals(b);'); + }, + ); + indent.newln(); + } + + void _writeDeepHashCode(Indent indent) { + indent.writeScoped('static int pigeonDeepHashCode(Object value) {', '}', () { + indent.writeln('if (value == null) { return 0; }'); + indent.writeScoped('if (value instanceof byte[]) {', '}', () { + indent.writeln('return Arrays.hashCode((byte[]) value);'); + }); + indent.writeScoped('if (value instanceof int[]) {', '}', () { + indent.writeln('return Arrays.hashCode((int[]) value);'); + }); + indent.writeScoped('if (value instanceof long[]) {', '}', () { + indent.writeln('return Arrays.hashCode((long[]) value);'); + }); + indent.writeScoped('if (value instanceof double[]) {', '}', () { + indent.writeln('double[] da = (double[]) value;'); + indent.writeln('int result = 1;'); + indent.writeScoped('for (double d : da) {', '}', () { + indent.writeln('result = 31 * result + pigeonDoubleHashCode(d);'); + }); + indent.writeln('return result;'); + }); + indent.writeScoped('if (value instanceof List) {', '}', () { + indent.writeln('int result = 1;'); + indent.writeScoped('for (Object item : (List) value) {', '}', () { + indent.writeln('result = 31 * result + pigeonDeepHashCode(item);'); + }); + indent.writeln('return result;'); + }); + indent.writeScoped('if (value instanceof Map) {', '}', () { + indent.writeln('int result = 0;'); + indent.writeScoped( + 'for (Map.Entry entry : ((Map) value).entrySet()) {', + '}', + () { + indent.writeln( + 'result += ((pigeonDeepHashCode(entry.getKey()) * 31) ^ pigeonDeepHashCode(entry.getValue()));', + ); + }, + ); + indent.writeln('return result;'); + }); + indent.writeScoped('if (value instanceof Object[]) {', '}', () { + indent.writeln('int result = 1;'); + indent.writeScoped('for (Object item : (Object[]) value) {', '}', () { + indent.writeln('result = 31 * result + pigeonDeepHashCode(item);'); + }); + indent.writeln('return result;'); + }); + indent.writeScoped('if (value instanceof Double) {', '}', () { + indent.writeln('return pigeonDoubleHashCode((double) value);'); + }); + indent.writeScoped('if (value instanceof Float) {', '}', () { + indent.writeln('return pigeonFloatHashCode((float) value);'); + }); + indent.writeln('return value.hashCode();'); + }); + indent.newln(); + } + + void _writeNumberHelpers(Indent indent) { + indent.writeScoped( + 'static boolean pigeonDoubleEquals(double a, double b) {', + '}', + () { + indent.writeln('// Normalize -0.0 to 0.0 and handle NaN equality.'); + indent.writeln( + 'return (a == 0.0 ? 0.0 : a) == (b == 0.0 ? 0.0 : b) || (Double.isNaN(a) && Double.isNaN(b));', + ); + }, + ); + indent.newln(); + indent.writeScoped( + 'static boolean pigeonFloatEquals(float a, float b) {', + '}', + () { + indent.writeln('// Normalize -0.0 to 0.0 and handle NaN equality.'); + indent.writeln( + 'return (a == 0.0f ? 0.0f : a) == (b == 0.0f ? 0.0f : b) || (Float.isNaN(a) && Float.isNaN(b));', + ); + }, + ); + indent.newln(); + indent.writeScoped('static int pigeonDoubleHashCode(double d) {', '}', () { + indent.writeln( + '// Normalize -0.0 to 0.0 and handle NaN to ensure consistent hash codes.', + ); + indent.writeScoped('if (d == 0.0) {', '}', () { + indent.writeln('d = 0.0;'); + }); + indent.writeln('long bits = Double.doubleToLongBits(d);'); + indent.writeln('return (int) (bits ^ (bits >>> 32));'); + }); + indent.newln(); + indent.writeScoped('static int pigeonFloatHashCode(float f) {', '}', () { + indent.writeln( + '// Normalize -0.0 to 0.0 and handle NaN to ensure consistent hash codes.', + ); + indent.writeScoped('if (f == 0.0f) {', '}', () { + indent.writeln('f = 0.0f;'); + }); + indent.writeln('return Float.floatToIntBits(f);'); + }); + indent.newln(); + } + void _writeClassBuilder( InternalJavaOptions generatorOptions, Root root, @@ -728,6 +962,7 @@ if (wrapped == null) { /// Writes the code for a flutter [Api], [api]. /// Example: + /// ```java /// public static final class Foo { /// public Foo(BinaryMessenger argBinaryMessenger) {...} /// public interface Result { @@ -735,6 +970,7 @@ if (wrapped == null) { /// } /// public int add(int x, int y, Result result) {...} /// } + /// ``` @override void writeFlutterApi( InternalJavaOptions generatorOptions, @@ -1372,10 +1608,6 @@ String _javaTypeForBuiltinGenericDartType( } } -bool _javaTypeIsArray(TypeDeclaration type) { - return _javaTypeForBuiltinDartType(type)?.endsWith('[]') ?? false; -} - String? _javaTypeForBuiltinDartType(TypeDeclaration type) { const javaTypeForDartTypeMap = { 'bool': 'Boolean', diff --git a/packages/pigeon/lib/src/kotlin/kotlin_generator.dart b/packages/pigeon/lib/src/kotlin/kotlin_generator.dart index 5ad4f3ee88a4..fee33c6b66d6 100644 --- a/packages/pigeon/lib/src/kotlin/kotlin_generator.dart +++ b/packages/pigeon/lib/src/kotlin/kotlin_generator.dart @@ -345,19 +345,49 @@ class KotlinGenerator extends StructuredGenerator { required String dartPackageName, }) { indent.writeScoped('override fun equals(other: Any?): Boolean {', '}', () { - indent.writeScoped('if (other !is ${classDefinition.name}) {', '}', () { - indent.writeln('return false'); - }); + indent.writeScoped( + 'if (other == null || other.javaClass != javaClass) {', + '}', + () { + indent.writeln('return false'); + }, + ); indent.writeScoped('if (this === other) {', '}', () { indent.writeln('return true'); }); - indent.write( - 'return ${_getUtilsClassName(generatorOptions)}.deepEquals(toList(), other.toList())', + + indent.writeln('val other = other as ${classDefinition.name}'); + final Iterable fields = getFieldsInSerializationOrder( + classDefinition, ); + if (fields.isEmpty) { + indent.writeln('return true'); + } else { + final String utils = _getUtilsClassName(generatorOptions); + final String comparisons = fields + .map( + (NamedType field) => + '$utils.deepEquals(this.${field.name}, other.${field.name})', + ) + .join(' && '); + indent.writeln('return $comparisons'); + } }); indent.newln(); - indent.writeln('override fun hashCode(): Int = toList().hashCode()'); + indent.writeScoped('override fun hashCode(): Int {', '}', () { + final Iterable fields = getFieldsInSerializationOrder( + classDefinition, + ); + final String utils = _getUtilsClassName(generatorOptions); + indent.writeln('var result = javaClass.hashCode()'); + for (final field in fields) { + indent.writeln( + 'result = 31 * result + $utils.deepHash(this.${field.name})', + ); + } + indent.writeln('return result'); + }); } void _writeDataClassSignature( @@ -1342,35 +1372,157 @@ if (wrapped == null) { void _writeDeepEquals(InternalKotlinOptions generatorOptions, Indent indent) { indent.format(''' fun deepEquals(a: Any?, b: Any?): Boolean { + if (a === b) { + return true + } + if (a == null || b == null) { + return false + } if (a is ByteArray && b is ByteArray) { - return a.contentEquals(b) + return a.contentEquals(b) } if (a is IntArray && b is IntArray) { - return a.contentEquals(b) + return a.contentEquals(b) } if (a is LongArray && b is LongArray) { - return a.contentEquals(b) + return a.contentEquals(b) } if (a is DoubleArray && b is DoubleArray) { - return a.contentEquals(b) + if (a.size != b.size) return false + for (i in a.indices) { + if (!doubleEquals(a[i], b[i])) return false + } + return true + } + if (a is FloatArray && b is FloatArray) { + if (a.size != b.size) return false + for (i in a.indices) { + if (!floatEquals(a[i], b[i])) return false + } + return true } if (a is Array<*> && b is Array<*>) { - return a.size == b.size && - a.indices.all{ deepEquals(a[it], b[it]) } + if (a.size != b.size) return false + for (i in a.indices) { + if (!deepEquals(a[i], b[i])) return false + } + return true } if (a is List<*> && b is List<*>) { - return a.size == b.size && - a.indices.all{ deepEquals(a[it], b[it]) } + if (a.size != b.size) return false + val iterA = a.iterator() + val iterB = b.iterator() + while (iterA.hasNext() && iterB.hasNext()) { + if (!deepEquals(iterA.next(), iterB.next())) return false + } + return true } if (a is Map<*, *> && b is Map<*, *>) { - return a.size == b.size && a.all { - (b as Map).contains(it.key) && - deepEquals(it.value, b[it.key]) + if (a.size != b.size) return false + for (entry in a) { + val key = entry.key + var found = false + for (bEntry in b) { + if (deepEquals(key, bEntry.key)) { + if (deepEquals(entry.value, bEntry.value)) { + found = true + break + } else { + return false + } + } + } + if (!found) return false } + return true + } + if (a is Double && b is Double) { + return doubleEquals(a, b) + } + if (a is Float && b is Float) { + return floatEquals(a, b) } return a == b } - '''); +'''); + } + + void _writeDeepHash(InternalKotlinOptions generatorOptions, Indent indent) { + indent.format(''' +fun deepHash(value: Any?): Int { + return when (value) { + null -> 0 + is ByteArray -> value.contentHashCode() + is IntArray -> value.contentHashCode() + is LongArray -> value.contentHashCode() + is DoubleArray -> { + var result = 1 + for (item in value) { + result = 31 * result + doubleHash(item) + } + result + } + is FloatArray -> { + var result = 1 + for (item in value) { + result = 31 * result + floatHash(item) + } + result + } + is Array<*> -> { + var result = 1 + for (item in value) { + result = 31 * result + deepHash(item) + } + result + } + is List<*> -> { + var result = 1 + for (item in value) { + result = 31 * result + deepHash(item) + } + result + } + is Map<*, *> -> { + var result = 0 + for (entry in value) { + result += ((deepHash(entry.key) * 31) xor deepHash(entry.value)) + } + result + } + is Double -> doubleHash(value) + is Float -> floatHash(value) + else -> value.hashCode() + } +} +'''); + } + + void _writeNumberHelpers(Indent indent) { + indent.format(''' +fun doubleEquals(a: Double, b: Double): Boolean { + // Normalize -0.0 to 0.0 and handle NaN equality. + return (if (a == 0.0) 0.0 else a) == (if (b == 0.0) 0.0 else b) || (a.isNaN() && b.isNaN()) +} + +fun floatEquals(a: Float, b: Float): Boolean { + // Normalize -0.0 to 0.0 and handle NaN equality. + return (if (a == 0.0f) 0.0f else a) == (if (b == 0.0f) 0.0f else b) || (a.isNaN() && b.isNaN()) +} + +fun doubleHash(d: Double): Int { + // Normalize -0.0 to 0.0 and handle NaN to ensure consistent hash codes. + val normalized = if (d == 0.0) 0.0 else d + val bits = java.lang.Double.doubleToLongBits(normalized) + return (bits xor (bits ushr 32)).toInt() +} + +fun floatHash(f: Float): Int { + // Normalize -0.0 to 0.0 and handle NaN to ensure consistent hash codes. + val normalized = if (f == 0.0f) 0.0f else f + return java.lang.Float.floatToIntBits(normalized) +} +'''); } @override @@ -1392,7 +1544,9 @@ fun deepEquals(a: Any?, b: Any?): Boolean { _writeWrapError(generatorOptions, indent); } if (root.classes.isNotEmpty) { + _writeNumberHelpers(indent); _writeDeepEquals(generatorOptions, indent); + _writeDeepHash(generatorOptions, indent); } }, ); diff --git a/packages/pigeon/lib/src/objc/objc_generator.dart b/packages/pigeon/lib/src/objc/objc_generator.dart index e76459a19dc9..af0ad6d1ea2a 100644 --- a/packages/pigeon/lib/src/objc/objc_generator.dart +++ b/packages/pigeon/lib/src/objc/objc_generator.dart @@ -518,6 +518,8 @@ class ObjcSourceGenerator extends StructuredGenerator { indent.writeln('@import Flutter;'); indent.writeln('#endif'); indent.newln(); + _writeDeepEquals(indent); + _writeDeepHash(indent); } @override @@ -614,10 +616,76 @@ class ObjcSourceGenerator extends StructuredGenerator { classDefinition, dartPackageName: dartPackageName, ); + _writeObjcEquality(generatorOptions, indent, classDefinition); indent.writeln('@end'); indent.newln(); } + void _writeObjcEquality( + InternalObjcOptions generatorOptions, + Indent indent, + Class classDefinition, + ) { + final String className = _className( + generatorOptions.prefix, + classDefinition.name, + ); + indent.write('- (BOOL)isEqual:(id)object '); + indent.addScoped('{', '}', () { + indent.writeScoped('if (self == object) {', '}', () { + indent.writeln('return YES;'); + }); + indent.writeScoped( + 'if (![object isKindOfClass:[self class]]) {', + '}', + () { + indent.writeln('return NO;'); + }, + ); + indent.writeln('$className *other = ($className *)object;'); + final Iterable checks = classDefinition.fields.map(( + NamedType field, + ) { + final String name = field.name; + if (_usesPrimitive(field.type)) { + if (field.type.baseName == 'double') { + return '(self.$name == other.$name || (isnan(self.$name) && isnan(other.$name)))'; + } + return 'self.$name == other.$name'; + } else { + return 'FLTPigeonDeepEquals(self.$name, other.$name)'; + } + }); + if (checks.isEmpty) { + indent.writeln('return YES;'); + } else { + indent.writeln('return ${checks.join(' && ')};'); + } + }); + indent.newln(); + indent.write('- (NSUInteger)hash '); + indent.addScoped('{', '}', () { + indent.writeln('NSUInteger result = [self class].hash;'); + for (final NamedType field in classDefinition.fields) { + final String name = field.name; + if (_usesPrimitive(field.type)) { + if (field.type.baseName == 'double') { + indent.writeln( + 'result = result * 31 + (isnan(self.$name) ? (NSUInteger)0x7FF8000000000000 : @(self.$name).hash);', + ); + } else { + indent.writeln('result = result * 31 + @(self.$name).hash;'); + } + } else { + indent.writeln( + 'result = result * 31 + FLTPigeonDeepHash(self.$name);', + ); + } + } + indent.writeln('return result;'); + }); + } + @override void writeClassEncode( InternalObjcOptions generatorOptions, @@ -1601,6 +1669,104 @@ const Map _objcTypeForNonNullableDartTypeMap = 'Object': _ObjcType(baseName: 'id'), }; +void _writeDeepEquals(Indent indent) { + indent.format(''' +static BOOL __attribute__((unused)) FLTPigeonDeepEquals(id _Nullable a, id _Nullable b) { + if (a == b) { + return YES; + } + if (a == nil) { + return b == [NSNull null]; + } + if (b == nil) { + return a == [NSNull null]; + } + if ([a isKindOfClass:[NSNumber class]] && [b isKindOfClass:[NSNumber class]]) { + return [a isEqual:b] || (isnan([(NSNumber *)a doubleValue]) && isnan([(NSNumber *)b doubleValue])); + } + if ([a isKindOfClass:[NSArray class]] && [b isKindOfClass:[NSArray class]]) { + NSArray *arrayA = (NSArray *)a; + NSArray *arrayB = (NSArray *)b; + if (arrayA.count != arrayB.count) { + return NO; + } + for (NSUInteger i = 0; i < arrayA.count; i++) { + if (!FLTPigeonDeepEquals(arrayA[i], arrayB[i])) { + return NO; + } + } + return YES; + } + if ([a isKindOfClass:[NSDictionary class]] && [b isKindOfClass:[NSDictionary class]]) { + NSDictionary *dictA = (NSDictionary *)a; + NSDictionary *dictB = (NSDictionary *)b; + if (dictA.count != dictB.count) { + return NO; + } + for (id keyA in dictA) { + id valueA = dictA[keyA]; + BOOL found = NO; + for (id keyB in dictB) { + if (FLTPigeonDeepEquals(keyA, keyB)) { + id valueB = dictB[keyB]; + if (FLTPigeonDeepEquals(valueA, valueB)) { + found = YES; + break; + } else { + return NO; + } + } + } + if (!found) { + return NO; + } + } + return YES; + } + return [a isEqual:b]; +} +'''); +} + +void _writeDeepHash(Indent indent) { + indent.format(''' +static NSUInteger __attribute__((unused)) FLTPigeonDeepHash(id _Nullable value) { + if (value == nil || value == (id)[NSNull null]) { + return 0; + } + if ([value isKindOfClass:[NSNumber class]]) { + NSNumber *n = (NSNumber *)value; + double d = n.doubleValue; + if (isnan(d)) { + // Normalize NaN to a consistent hash. + return (NSUInteger)0x7FF8000000000000; + } + if (d == 0.0) { + // Normalize -0.0 to 0.0 so they have the same hash code. + d = 0.0; + } + return @(d).hash; + } + if ([value isKindOfClass:[NSArray class]]) { + NSUInteger result = 1; + for (id item in (NSArray *)value) { + result = result * 31 + FLTPigeonDeepHash(item); + } + return result; + } + if ([value isKindOfClass:[NSDictionary class]]) { + NSUInteger result = 0; + NSDictionary *dict = (NSDictionary *)value; + for (id key in dict) { + result += ((FLTPigeonDeepHash(key) * 31) ^ FLTPigeonDeepHash(dict[key])); + } + return result; + } + return [value hash]; +} +'''); +} + bool _usesPrimitive(TypeDeclaration type) { // Only non-nullable types are unboxed. if (!type.isNullable) { diff --git a/packages/pigeon/lib/src/pigeon_lib_internal.dart b/packages/pigeon/lib/src/pigeon_lib_internal.dart index 75bbb96a293e..617a901f37cc 100644 --- a/packages/pigeon/lib/src/pigeon_lib_internal.dart +++ b/packages/pigeon/lib/src/pigeon_lib_internal.dart @@ -1579,7 +1579,7 @@ class RootBuilder extends dart_ast_visitor.RecursiveAstVisitor { _errors.add( Error( message: - 'API "${node.name.lexeme}" can only have one API annotation but contains: ${node.metadata}', + 'API "${node.namePart.typeName.lexeme}" can only have one API annotation but contains: ${node.metadata}', lineNumber: calculateLineNumber(source, node.offset), ), ); @@ -1606,7 +1606,7 @@ class RootBuilder extends dart_ast_visitor.RecursiveAstVisitor { } _currentApi = AstHostApi( - name: node.name.lexeme, + name: node.namePart.typeName.lexeme, methods: [], dartHostTestHandler: dartHostTestHandler, documentationComments: _documentationCommentsParser( @@ -1615,7 +1615,7 @@ class RootBuilder extends dart_ast_visitor.RecursiveAstVisitor { ); } else if (_hasMetadata(node.metadata, 'FlutterApi')) { _currentApi = AstFlutterApi( - name: node.name.lexeme, + name: node.namePart.typeName.lexeme, methods: [], documentationComments: _documentationCommentsParser( node.documentationComment?.tokens, @@ -1642,7 +1642,7 @@ class RootBuilder extends dart_ast_visitor.RecursiveAstVisitor { _errors.add( Error( message: - 'ProxyApis should either set the super class in the annotation OR use extends: ("${node.name.lexeme}").', + 'ProxyApis should either set the super class in the annotation OR use extends: ("${node.namePart.typeName.lexeme}").', lineNumber: calculateLineNumber(source, node.offset), ), ); @@ -1713,7 +1713,7 @@ class RootBuilder extends dart_ast_visitor.RecursiveAstVisitor { } _currentApi = AstProxyApi( - name: node.name.lexeme, + name: node.namePart.typeName.lexeme, methods: [], constructors: [], fields: [], @@ -1760,7 +1760,7 @@ class RootBuilder extends dart_ast_visitor.RecursiveAstVisitor { ); } _currentApi = AstEventChannelApi( - name: node.name.lexeme, + name: node.namePart.typeName.lexeme, methods: [], swiftOptions: swiftOptions, kotlinOptions: kotlinOptions, @@ -1771,7 +1771,7 @@ class RootBuilder extends dart_ast_visitor.RecursiveAstVisitor { } } else { _currentClass = Class( - name: node.name.lexeme, + name: node.namePart.typeName.lexeme, fields: [], superClassName: node.implementsClause?.interfaces.first.name.toString() ?? @@ -1922,10 +1922,14 @@ class RootBuilder extends dart_ast_visitor.RecursiveAstVisitor { // resolved return type, via // `node.declaredFragment!.element.returnType`. String erroneousDeclaration = node.name.lexeme; - final dart_ast.AstNode? enclosingDeclaration = node.parent; + dart_ast.AstNode? enclosingDeclaration = node.parent; + while (enclosingDeclaration != null && + enclosingDeclaration is! dart_ast.ClassDeclaration) { + enclosingDeclaration = enclosingDeclaration.parent; + } if (enclosingDeclaration is dart_ast.ClassDeclaration) { erroneousDeclaration = - '${enclosingDeclaration.name}.$erroneousDeclaration'; + '${enclosingDeclaration.namePart.typeName}.$erroneousDeclaration'; } _errors.add( Error( @@ -1982,8 +1986,8 @@ class RootBuilder extends dart_ast_visitor.RecursiveAstVisitor { Object? visitEnumDeclaration(dart_ast.EnumDeclaration node) { _enums.add( Enum( - name: node.name.lexeme, - members: node.constants + name: node.namePart.typeName.lexeme, + members: node.body.constants .map( (dart_ast.EnumConstantDeclaration e) => EnumMember( name: e.name.lexeme, diff --git a/packages/pigeon/lib/src/swift/swift_generator.dart b/packages/pigeon/lib/src/swift/swift_generator.dart index 220f0ba8d6dd..45b968ed4d10 100644 --- a/packages/pigeon/lib/src/swift/swift_generator.dart +++ b/packages/pigeon/lib/src/swift/swift_generator.dart @@ -661,21 +661,46 @@ if (wrapped == nil) { 'static func == (lhs: ${classDefinition.name}, rhs: ${classDefinition.name}) -> Bool {', '}', () { + indent.writeScoped( + 'if Swift.type(of: lhs) != Swift.type(of: rhs) {', + '}', + () { + indent.writeln('return false'); + }, + ); if (classDefinition.isSwiftClass) { indent.writeScoped('if (lhs === rhs) {', '}', () { indent.writeln('return true'); }); } - indent.write( - 'return deepEquals${generatorOptions.fileSpecificClassNameComponent}(lhs.toList(), rhs.toList())', + final Iterable fields = getFieldsInSerializationOrder( + classDefinition, ); + if (fields.isEmpty) { + indent.writeln('return true'); + } else { + final String comparisons = fields + .map( + (NamedType field) => + 'deepEquals${generatorOptions.fileSpecificClassNameComponent ?? ''}(lhs.${field.name}, rhs.${field.name})', + ) + .join(' && '); + indent.writeln('return $comparisons'); + } }, ); + indent.newln(); indent.writeScoped('func hash(into hasher: inout Hasher) {', '}', () { - indent.writeln( - 'deepHash${generatorOptions.fileSpecificClassNameComponent}(value: toList(), hasher: &hasher)', + indent.writeln('hasher.combine("${classDefinition.name}")'); + final Iterable fields = getFieldsInSerializationOrder( + classDefinition, ); + for (final field in fields) { + indent.writeln( + 'deepHash${generatorOptions.fileSpecificClassNameComponent ?? ''}(value: ${field.name}, hasher: &hasher)', + ); + } }); } @@ -1449,7 +1474,7 @@ if (wrapped == nil) { indent.write('return '); indent.addScoped('[', ']', () { indent.writeln(r'"\(error)",'); - indent.writeln(r'"\(type(of: error))",'); + indent.writeln(r'"\(Swift.type(of: error))",'); indent.writeln(r'"Stacktrace: \(Thread.callStackSymbols)",'); }); }); @@ -1482,8 +1507,29 @@ private func nilOrValue(_ value: Any?) -> T? { } void _writeDeepEquals(InternalSwiftOptions generatorOptions, Indent indent) { + final deepEqualsName = + 'deepEquals${generatorOptions.fileSpecificClassNameComponent ?? ''}'; + final deepHashName = + 'deepHash${generatorOptions.fileSpecificClassNameComponent ?? ''}'; + final doubleEqualsName = + 'doubleEquals${generatorOptions.fileSpecificClassNameComponent ?? ''}'; + final doubleHashName = + 'doubleHash${generatorOptions.fileSpecificClassNameComponent ?? ''}'; indent.format(''' -func deepEquals${generatorOptions.fileSpecificClassNameComponent}(_ lhs: Any?, _ rhs: Any?) -> Bool { +private func $doubleEqualsName(_ lhs: Double, _ rhs: Double) -> Bool { + return (lhs.isNaN && rhs.isNaN) || lhs == rhs +} + +private func $doubleHashName(_ value: Double, _ hasher: inout Hasher) { + if value.isNaN { + hasher.combine(0x7FF8000000000000) + } else { + // Normalize -0.0 to 0.0 + hasher.combine(value == 0 ? 0 : value) + } +} + +func $deepEqualsName(_ lhs: Any?, _ rhs: Any?) -> Bool { let cleanLhs = nilOrValue(lhs) as Any? let cleanRhs = nilOrValue(rhs) as Any? switch (cleanLhs, cleanRhs) { @@ -1493,59 +1539,92 @@ func deepEquals${generatorOptions.fileSpecificClassNameComponent}(_ lhs: Any?, _ case (nil, _), (_, nil): return false - case is (Void, Void): + case (let lhs as AnyObject, let rhs as AnyObject) where lhs === rhs: return true - case let (cleanLhsHashable, cleanRhsHashable) as (AnyHashable, AnyHashable): - return cleanLhsHashable == cleanRhsHashable + case is (Void, Void): + return true - case let (cleanLhsArray, cleanRhsArray) as ([Any?], [Any?]): - guard cleanLhsArray.count == cleanRhsArray.count else { return false } - for (index, element) in cleanLhsArray.enumerated() { - if !deepEquals${generatorOptions.fileSpecificClassNameComponent}(element, cleanRhsArray[index]) { + case (let lhsArray, let rhsArray) as ([Any?], [Any?]): + guard lhsArray.count == rhsArray.count else { return false } + for (index, element) in lhsArray.enumerated() { + if !$deepEqualsName(element, rhsArray[index]) { return false } } return true - case let (cleanLhsDictionary, cleanRhsDictionary) as ([AnyHashable: Any?], [AnyHashable: Any?]): - guard cleanLhsDictionary.count == cleanRhsDictionary.count else { return false } - for (key, cleanLhsValue) in cleanLhsDictionary { - guard cleanRhsDictionary.index(forKey: key) != nil else { return false } - if !deepEquals${generatorOptions.fileSpecificClassNameComponent}(cleanLhsValue, cleanRhsDictionary[key]!) { + case (let lhsArray, let rhsArray) as ([Double], [Double]): + guard lhsArray.count == rhsArray.count else { return false } + for (index, element) in lhsArray.enumerated() { + if !$doubleEqualsName(element, rhsArray[index]) { return false } } return true + case (let lhsDictionary, let rhsDictionary) as ([AnyHashable: Any?], [AnyHashable: Any?]): + guard lhsDictionary.count == rhsDictionary.count else { return false } + for (lhsKey, lhsValue) in lhsDictionary { + var found = false + for (rhsKey, rhsValue) in rhsDictionary { + if $deepEqualsName(lhsKey, rhsKey) { + if $deepEqualsName(lhsValue, rhsValue) { + found = true + break + } else { + return false + } + } + } + if !found { return false } + } + return true + + case (let lhs as Double, let rhs as Double): + return $doubleEqualsName(lhs, rhs) + + case (let lhsHashable, let rhsHashable) as (AnyHashable, AnyHashable): + return lhsHashable == rhsHashable + default: - // Any other type shouldn't be able to be used with pigeon. File an issue if you find this to be untrue. return false } } -func deepHash${generatorOptions.fileSpecificClassNameComponent}(value: Any?, hasher: inout Hasher) { - if let valueList = value as? [AnyHashable] { - for item in valueList { deepHash${generatorOptions.fileSpecificClassNameComponent}(value: item, hasher: &hasher) } - return - } - - if let valueDict = value as? [AnyHashable: AnyHashable] { - for key in valueDict.keys { - hasher.combine(key) - deepHash${generatorOptions.fileSpecificClassNameComponent}(value: valueDict[key]!, hasher: &hasher) +func $deepHashName(value: Any?, hasher: inout Hasher) { + let cleanValue = nilOrValue(value) as Any? + if let cleanValue = cleanValue { + if let doubleValue = cleanValue as? Double { + $doubleHashName(doubleValue, &hasher) + } else if let valueList = cleanValue as? [Any?] { + for item in valueList { + $deepHashName(value: item, hasher: &hasher) + } + } else if let valueList = cleanValue as? [Double] { + for item in valueList { + $doubleHashName(item, &hasher) + } + } else if let valueDict = cleanValue as? [AnyHashable: Any?] { + var result = 0 + for (key, value) in valueDict { + var entryKeyHasher = Hasher() + $deepHashName(value: key, hasher: &entryKeyHasher) + var entryValueHasher = Hasher() + $deepHashName(value: value, hasher: &entryValueHasher) + result = result &+ ((entryKeyHasher.finalize() &* 31) ^ entryValueHasher.finalize()) + } + hasher.combine(result) + } else if let hashableValue = cleanValue as? AnyHashable { + hasher.combine(hashableValue) + } else { + hasher.combine(String(describing: cleanValue)) } - return - } - - if let hashableValue = value as? AnyHashable { - hasher.combine(hashableValue.hashValue) + } else { + hasher.combine(0) } - - return hasher.combine(String(describing: value)) } - - '''); +'''); } @override diff --git a/packages/pigeon/pigeons/core_tests.dart b/packages/pigeon/pigeons/core_tests.dart index 8795c8de900a..f55c0bbfd519 100644 --- a/packages/pigeon/pigeons/core_tests.dart +++ b/packages/pigeon/pigeons/core_tests.dart @@ -435,6 +435,17 @@ abstract class HostIntegrationCoreApi { // ========== Synchronous nullable method tests ========== + /// Returns the result of platform-side equality check. + bool areAllNullableTypesEqual(AllNullableTypes a, AllNullableTypes b); + + /// Returns the platform-side hash code for the given object. + int getAllNullableTypesHash(AllNullableTypes value); + + /// Returns the platform-side hash code for the given object. + int getAllNullableTypesWithoutRecursionHash( + AllNullableTypesWithoutRecursion value, + ); + /// Returns the passed object, to test serialization and deserialization. @ObjCSelector('echoAllNullableTypes:') @SwiftFunction('echo(_:)') diff --git a/packages/pigeon/platform_tests/alternate_language_test_plugin/android/build.gradle b/packages/pigeon/platform_tests/alternate_language_test_plugin/android/build.gradle.kts similarity index 61% rename from packages/pigeon/platform_tests/alternate_language_test_plugin/android/build.gradle rename to packages/pigeon/platform_tests/alternate_language_test_plugin/android/build.gradle.kts index 65fe42297512..1925992c30a2 100644 --- a/packages/pigeon/platform_tests/alternate_language_test_plugin/android/build.gradle +++ b/packages/pigeon/platform_tests/alternate_language_test_plugin/android/build.gradle.kts @@ -12,14 +12,16 @@ buildscript { } } -rootProject.allprojects { +allprojects { repositories { google() mavenCentral() } } -apply plugin: 'com.android.library' +plugins { + id("com.android.library") +} android { namespace = "com.example.alternate_language_test_plugin" @@ -35,13 +37,15 @@ android { } testOptions { - unitTests.includeAndroidResources = true - unitTests.returnDefaultValues = true - unitTests.all { - testLogging { - events "passed", "skipped", "failed", "standardOut", "standardError" - outputs.upToDateWhen {false} - showStandardStreams = true + unitTests { + isIncludeAndroidResources = true + isReturnDefaultValues = true + all { + it.outputs.upToDateWhen { false } + it.testLogging { + events("passed", "skipped", "failed", "standardOut", "standardError") + showStandardStreams = true + } } } } @@ -49,7 +53,7 @@ android { lint { checkAllWarnings = true warningsAsErrors = true - disable 'AndroidGradlePluginVersion', 'InvalidPackage', 'GradleDependency', 'NewerVersionAvailable' + disable.addAll(setOf("AndroidGradlePluginVersion", "InvalidPackage", "GradleDependency", "NewerVersionAvailable")) } dependencies { diff --git a/packages/pigeon/platform_tests/alternate_language_test_plugin/android/settings.gradle b/packages/pigeon/platform_tests/alternate_language_test_plugin/android/settings.gradle deleted file mode 100644 index 0f10659c4e4e..000000000000 --- a/packages/pigeon/platform_tests/alternate_language_test_plugin/android/settings.gradle +++ /dev/null @@ -1 +0,0 @@ -rootProject.name = 'alternate_language_test_plugin' diff --git a/packages/pigeon/platform_tests/alternate_language_test_plugin/android/settings.gradle.kts b/packages/pigeon/platform_tests/alternate_language_test_plugin/android/settings.gradle.kts new file mode 100644 index 000000000000..e6c1cb2b5f2e --- /dev/null +++ b/packages/pigeon/platform_tests/alternate_language_test_plugin/android/settings.gradle.kts @@ -0,0 +1 @@ +rootProject.name = "alternate_language_test_plugin" diff --git a/packages/pigeon/platform_tests/alternate_language_test_plugin/android/src/main/java/com/example/alternate_language_test_plugin/AlternateLanguageTestPlugin.java b/packages/pigeon/platform_tests/alternate_language_test_plugin/android/src/main/java/com/example/alternate_language_test_plugin/AlternateLanguageTestPlugin.java index 4ece8628d399..5c46688a6d95 100644 --- a/packages/pigeon/platform_tests/alternate_language_test_plugin/android/src/main/java/com/example/alternate_language_test_plugin/AlternateLanguageTestPlugin.java +++ b/packages/pigeon/platform_tests/alternate_language_test_plugin/android/src/main/java/com/example/alternate_language_test_plugin/AlternateLanguageTestPlugin.java @@ -61,6 +61,23 @@ public void noop() {} return everything; } + @Override + public @NonNull Boolean areAllNullableTypesEqual( + @NonNull AllNullableTypes a, @NonNull AllNullableTypes b) { + return a.equals(b); + } + + @Override + public @NonNull Long getAllNullableTypesHash(@NonNull AllNullableTypes value) { + return (long) value.hashCode(); + } + + @Override + public @NonNull Long getAllNullableTypesWithoutRecursionHash( + @NonNull AllNullableTypesWithoutRecursion value) { + return (long) value.hashCode(); + } + @Override public @Nullable AllNullableTypesWithoutRecursion echoAllNullableTypesWithoutRecursion( @Nullable AllNullableTypesWithoutRecursion everything) { diff --git a/packages/pigeon/platform_tests/alternate_language_test_plugin/android/src/main/java/com/example/alternate_language_test_plugin/CoreTests.java b/packages/pigeon/platform_tests/alternate_language_test_plugin/android/src/main/java/com/example/alternate_language_test_plugin/CoreTests.java index 66e0f3516fa4..8b3825849e95 100644 --- a/packages/pigeon/platform_tests/alternate_language_test_plugin/android/src/main/java/com/example/alternate_language_test_plugin/CoreTests.java +++ b/packages/pigeon/platform_tests/alternate_language_test_plugin/android/src/main/java/com/example/alternate_language_test_plugin/CoreTests.java @@ -26,11 +26,167 @@ import java.util.Collections; import java.util.List; import java.util.Map; -import java.util.Objects; /** Generated class from Pigeon. */ @SuppressWarnings({"unused", "unchecked", "CodeBlock2Expr", "RedundantSuppression", "serial"}) public class CoreTests { + static boolean pigeonDoubleEquals(double a, double b) { + // Normalize -0.0 to 0.0 and handle NaN equality. + return (a == 0.0 ? 0.0 : a) == (b == 0.0 ? 0.0 : b) || (Double.isNaN(a) && Double.isNaN(b)); + } + + static boolean pigeonFloatEquals(float a, float b) { + // Normalize -0.0 to 0.0 and handle NaN equality. + return (a == 0.0f ? 0.0f : a) == (b == 0.0f ? 0.0f : b) || (Float.isNaN(a) && Float.isNaN(b)); + } + + static int pigeonDoubleHashCode(double d) { + // Normalize -0.0 to 0.0 and handle NaN to ensure consistent hash codes. + if (d == 0.0) { + d = 0.0; + } + long bits = Double.doubleToLongBits(d); + return (int) (bits ^ (bits >>> 32)); + } + + static int pigeonFloatHashCode(float f) { + // Normalize -0.0 to 0.0 and handle NaN to ensure consistent hash codes. + if (f == 0.0f) { + f = 0.0f; + } + return Float.floatToIntBits(f); + } + + static boolean pigeonDeepEquals(Object a, Object b) { + if (a == b) { + return true; + } + if (a == null || b == null) { + return false; + } + if (a instanceof byte[] && b instanceof byte[]) { + return Arrays.equals((byte[]) a, (byte[]) b); + } + if (a instanceof int[] && b instanceof int[]) { + return Arrays.equals((int[]) a, (int[]) b); + } + if (a instanceof long[] && b instanceof long[]) { + return Arrays.equals((long[]) a, (long[]) b); + } + if (a instanceof double[] && b instanceof double[]) { + double[] da = (double[]) a; + double[] db = (double[]) b; + if (da.length != db.length) { + return false; + } + for (int i = 0; i < da.length; i++) { + if (!pigeonDoubleEquals(da[i], db[i])) { + return false; + } + } + return true; + } + if (a instanceof List && b instanceof List) { + List listA = (List) a; + List listB = (List) b; + if (listA.size() != listB.size()) { + return false; + } + for (int i = 0; i < listA.size(); i++) { + if (!pigeonDeepEquals(listA.get(i), listB.get(i))) { + return false; + } + } + return true; + } + if (a instanceof Map && b instanceof Map) { + Map mapA = (Map) a; + Map mapB = (Map) b; + if (mapA.size() != mapB.size()) { + return false; + } + for (Map.Entry entryA : mapA.entrySet()) { + Object keyA = entryA.getKey(); + Object valueA = entryA.getValue(); + boolean found = false; + for (Map.Entry entryB : mapB.entrySet()) { + Object keyB = entryB.getKey(); + if (pigeonDeepEquals(keyA, keyB)) { + Object valueB = entryB.getValue(); + if (pigeonDeepEquals(valueA, valueB)) { + found = true; + break; + } else { + return false; + } + } + } + if (!found) { + return false; + } + } + return true; + } + if (a instanceof Double && b instanceof Double) { + return pigeonDoubleEquals((double) a, (double) b); + } + if (a instanceof Float && b instanceof Float) { + return pigeonFloatEquals((float) a, (float) b); + } + return a.equals(b); + } + + static int pigeonDeepHashCode(Object value) { + if (value == null) { + return 0; + } + if (value instanceof byte[]) { + return Arrays.hashCode((byte[]) value); + } + if (value instanceof int[]) { + return Arrays.hashCode((int[]) value); + } + if (value instanceof long[]) { + return Arrays.hashCode((long[]) value); + } + if (value instanceof double[]) { + double[] da = (double[]) value; + int result = 1; + for (double d : da) { + result = 31 * result + pigeonDoubleHashCode(d); + } + return result; + } + if (value instanceof List) { + int result = 1; + for (Object item : (List) value) { + result = 31 * result + pigeonDeepHashCode(item); + } + return result; + } + if (value instanceof Map) { + int result = 0; + for (Map.Entry entry : ((Map) value).entrySet()) { + result += + ((pigeonDeepHashCode(entry.getKey()) * 31) ^ pigeonDeepHashCode(entry.getValue())); + } + return result; + } + if (value instanceof Object[]) { + int result = 1; + for (Object item : (Object[]) value) { + result = 31 * result + pigeonDeepHashCode(item); + } + return result; + } + if (value instanceof Double) { + return pigeonDoubleHashCode((double) value); + } + if (value instanceof Float) { + return pigeonFloatHashCode((float) value); + } + return value.hashCode(); + } /** Error class for passing custom error details to Flutter via a thrown PlatformException. */ public static class FlutterError extends RuntimeException { @@ -120,12 +276,13 @@ public boolean equals(Object o) { return false; } UnusedClass that = (UnusedClass) o; - return Objects.equals(aField, that.aField); + return pigeonDeepEquals(aField, that.aField); } @Override public int hashCode() { - return Objects.hash(aField); + Object[] fields = new Object[] {getClass(), aField}; + return pigeonDeepHashCode(fields); } public static final class Builder { @@ -542,69 +699,71 @@ public boolean equals(Object o) { return false; } AllTypes that = (AllTypes) o; - return aBool.equals(that.aBool) - && anInt.equals(that.anInt) - && anInt64.equals(that.anInt64) - && aDouble.equals(that.aDouble) - && Arrays.equals(aByteArray, that.aByteArray) - && Arrays.equals(a4ByteArray, that.a4ByteArray) - && Arrays.equals(a8ByteArray, that.a8ByteArray) - && Arrays.equals(aFloatArray, that.aFloatArray) - && anEnum.equals(that.anEnum) - && anotherEnum.equals(that.anotherEnum) - && aString.equals(that.aString) - && anObject.equals(that.anObject) - && list.equals(that.list) - && stringList.equals(that.stringList) - && intList.equals(that.intList) - && doubleList.equals(that.doubleList) - && boolList.equals(that.boolList) - && enumList.equals(that.enumList) - && objectList.equals(that.objectList) - && listList.equals(that.listList) - && mapList.equals(that.mapList) - && map.equals(that.map) - && stringMap.equals(that.stringMap) - && intMap.equals(that.intMap) - && enumMap.equals(that.enumMap) - && objectMap.equals(that.objectMap) - && listMap.equals(that.listMap) - && mapMap.equals(that.mapMap); + return pigeonDeepEquals(aBool, that.aBool) + && pigeonDeepEquals(anInt, that.anInt) + && pigeonDeepEquals(anInt64, that.anInt64) + && pigeonDeepEquals(aDouble, that.aDouble) + && pigeonDeepEquals(aByteArray, that.aByteArray) + && pigeonDeepEquals(a4ByteArray, that.a4ByteArray) + && pigeonDeepEquals(a8ByteArray, that.a8ByteArray) + && pigeonDeepEquals(aFloatArray, that.aFloatArray) + && pigeonDeepEquals(anEnum, that.anEnum) + && pigeonDeepEquals(anotherEnum, that.anotherEnum) + && pigeonDeepEquals(aString, that.aString) + && pigeonDeepEquals(anObject, that.anObject) + && pigeonDeepEquals(list, that.list) + && pigeonDeepEquals(stringList, that.stringList) + && pigeonDeepEquals(intList, that.intList) + && pigeonDeepEquals(doubleList, that.doubleList) + && pigeonDeepEquals(boolList, that.boolList) + && pigeonDeepEquals(enumList, that.enumList) + && pigeonDeepEquals(objectList, that.objectList) + && pigeonDeepEquals(listList, that.listList) + && pigeonDeepEquals(mapList, that.mapList) + && pigeonDeepEquals(map, that.map) + && pigeonDeepEquals(stringMap, that.stringMap) + && pigeonDeepEquals(intMap, that.intMap) + && pigeonDeepEquals(enumMap, that.enumMap) + && pigeonDeepEquals(objectMap, that.objectMap) + && pigeonDeepEquals(listMap, that.listMap) + && pigeonDeepEquals(mapMap, that.mapMap); } @Override public int hashCode() { - int pigeonVar_result = - Objects.hash( - aBool, - anInt, - anInt64, - aDouble, - anEnum, - anotherEnum, - aString, - anObject, - list, - stringList, - intList, - doubleList, - boolList, - enumList, - objectList, - listList, - mapList, - map, - stringMap, - intMap, - enumMap, - objectMap, - listMap, - mapMap); - pigeonVar_result = 31 * pigeonVar_result + Arrays.hashCode(aByteArray); - pigeonVar_result = 31 * pigeonVar_result + Arrays.hashCode(a4ByteArray); - pigeonVar_result = 31 * pigeonVar_result + Arrays.hashCode(a8ByteArray); - pigeonVar_result = 31 * pigeonVar_result + Arrays.hashCode(aFloatArray); - return pigeonVar_result; + Object[] fields = + new Object[] { + getClass(), + aBool, + anInt, + anInt64, + aDouble, + aByteArray, + a4ByteArray, + a8ByteArray, + aFloatArray, + anEnum, + anotherEnum, + aString, + anObject, + list, + stringList, + intList, + doubleList, + boolList, + enumList, + objectList, + listList, + mapList, + map, + stringMap, + intMap, + enumMap, + objectMap, + listMap, + mapMap + }; + return pigeonDeepHashCode(fields); } public static final class Builder { @@ -1288,75 +1447,77 @@ public boolean equals(Object o) { return false; } AllNullableTypes that = (AllNullableTypes) o; - return Objects.equals(aNullableBool, that.aNullableBool) - && Objects.equals(aNullableInt, that.aNullableInt) - && Objects.equals(aNullableInt64, that.aNullableInt64) - && Objects.equals(aNullableDouble, that.aNullableDouble) - && Arrays.equals(aNullableByteArray, that.aNullableByteArray) - && Arrays.equals(aNullable4ByteArray, that.aNullable4ByteArray) - && Arrays.equals(aNullable8ByteArray, that.aNullable8ByteArray) - && Arrays.equals(aNullableFloatArray, that.aNullableFloatArray) - && Objects.equals(aNullableEnum, that.aNullableEnum) - && Objects.equals(anotherNullableEnum, that.anotherNullableEnum) - && Objects.equals(aNullableString, that.aNullableString) - && Objects.equals(aNullableObject, that.aNullableObject) - && Objects.equals(allNullableTypes, that.allNullableTypes) - && Objects.equals(list, that.list) - && Objects.equals(stringList, that.stringList) - && Objects.equals(intList, that.intList) - && Objects.equals(doubleList, that.doubleList) - && Objects.equals(boolList, that.boolList) - && Objects.equals(enumList, that.enumList) - && Objects.equals(objectList, that.objectList) - && Objects.equals(listList, that.listList) - && Objects.equals(mapList, that.mapList) - && Objects.equals(recursiveClassList, that.recursiveClassList) - && Objects.equals(map, that.map) - && Objects.equals(stringMap, that.stringMap) - && Objects.equals(intMap, that.intMap) - && Objects.equals(enumMap, that.enumMap) - && Objects.equals(objectMap, that.objectMap) - && Objects.equals(listMap, that.listMap) - && Objects.equals(mapMap, that.mapMap) - && Objects.equals(recursiveClassMap, that.recursiveClassMap); + return pigeonDeepEquals(aNullableBool, that.aNullableBool) + && pigeonDeepEquals(aNullableInt, that.aNullableInt) + && pigeonDeepEquals(aNullableInt64, that.aNullableInt64) + && pigeonDeepEquals(aNullableDouble, that.aNullableDouble) + && pigeonDeepEquals(aNullableByteArray, that.aNullableByteArray) + && pigeonDeepEquals(aNullable4ByteArray, that.aNullable4ByteArray) + && pigeonDeepEquals(aNullable8ByteArray, that.aNullable8ByteArray) + && pigeonDeepEquals(aNullableFloatArray, that.aNullableFloatArray) + && pigeonDeepEquals(aNullableEnum, that.aNullableEnum) + && pigeonDeepEquals(anotherNullableEnum, that.anotherNullableEnum) + && pigeonDeepEquals(aNullableString, that.aNullableString) + && pigeonDeepEquals(aNullableObject, that.aNullableObject) + && pigeonDeepEquals(allNullableTypes, that.allNullableTypes) + && pigeonDeepEquals(list, that.list) + && pigeonDeepEquals(stringList, that.stringList) + && pigeonDeepEquals(intList, that.intList) + && pigeonDeepEquals(doubleList, that.doubleList) + && pigeonDeepEquals(boolList, that.boolList) + && pigeonDeepEquals(enumList, that.enumList) + && pigeonDeepEquals(objectList, that.objectList) + && pigeonDeepEquals(listList, that.listList) + && pigeonDeepEquals(mapList, that.mapList) + && pigeonDeepEquals(recursiveClassList, that.recursiveClassList) + && pigeonDeepEquals(map, that.map) + && pigeonDeepEquals(stringMap, that.stringMap) + && pigeonDeepEquals(intMap, that.intMap) + && pigeonDeepEquals(enumMap, that.enumMap) + && pigeonDeepEquals(objectMap, that.objectMap) + && pigeonDeepEquals(listMap, that.listMap) + && pigeonDeepEquals(mapMap, that.mapMap) + && pigeonDeepEquals(recursiveClassMap, that.recursiveClassMap); } @Override public int hashCode() { - int pigeonVar_result = - Objects.hash( - aNullableBool, - aNullableInt, - aNullableInt64, - aNullableDouble, - aNullableEnum, - anotherNullableEnum, - aNullableString, - aNullableObject, - allNullableTypes, - list, - stringList, - intList, - doubleList, - boolList, - enumList, - objectList, - listList, - mapList, - recursiveClassList, - map, - stringMap, - intMap, - enumMap, - objectMap, - listMap, - mapMap, - recursiveClassMap); - pigeonVar_result = 31 * pigeonVar_result + Arrays.hashCode(aNullableByteArray); - pigeonVar_result = 31 * pigeonVar_result + Arrays.hashCode(aNullable4ByteArray); - pigeonVar_result = 31 * pigeonVar_result + Arrays.hashCode(aNullable8ByteArray); - pigeonVar_result = 31 * pigeonVar_result + Arrays.hashCode(aNullableFloatArray); - return pigeonVar_result; + Object[] fields = + new Object[] { + getClass(), + aNullableBool, + aNullableInt, + aNullableInt64, + aNullableDouble, + aNullableByteArray, + aNullable4ByteArray, + aNullable8ByteArray, + aNullableFloatArray, + aNullableEnum, + anotherNullableEnum, + aNullableString, + aNullableObject, + allNullableTypes, + list, + stringList, + intList, + doubleList, + boolList, + enumList, + objectList, + listList, + mapList, + recursiveClassList, + map, + stringMap, + intMap, + enumMap, + objectMap, + listMap, + mapMap, + recursiveClassMap + }; + return pigeonDeepHashCode(fields); } public static final class Builder { @@ -2048,69 +2209,71 @@ public boolean equals(Object o) { return false; } AllNullableTypesWithoutRecursion that = (AllNullableTypesWithoutRecursion) o; - return Objects.equals(aNullableBool, that.aNullableBool) - && Objects.equals(aNullableInt, that.aNullableInt) - && Objects.equals(aNullableInt64, that.aNullableInt64) - && Objects.equals(aNullableDouble, that.aNullableDouble) - && Arrays.equals(aNullableByteArray, that.aNullableByteArray) - && Arrays.equals(aNullable4ByteArray, that.aNullable4ByteArray) - && Arrays.equals(aNullable8ByteArray, that.aNullable8ByteArray) - && Arrays.equals(aNullableFloatArray, that.aNullableFloatArray) - && Objects.equals(aNullableEnum, that.aNullableEnum) - && Objects.equals(anotherNullableEnum, that.anotherNullableEnum) - && Objects.equals(aNullableString, that.aNullableString) - && Objects.equals(aNullableObject, that.aNullableObject) - && Objects.equals(list, that.list) - && Objects.equals(stringList, that.stringList) - && Objects.equals(intList, that.intList) - && Objects.equals(doubleList, that.doubleList) - && Objects.equals(boolList, that.boolList) - && Objects.equals(enumList, that.enumList) - && Objects.equals(objectList, that.objectList) - && Objects.equals(listList, that.listList) - && Objects.equals(mapList, that.mapList) - && Objects.equals(map, that.map) - && Objects.equals(stringMap, that.stringMap) - && Objects.equals(intMap, that.intMap) - && Objects.equals(enumMap, that.enumMap) - && Objects.equals(objectMap, that.objectMap) - && Objects.equals(listMap, that.listMap) - && Objects.equals(mapMap, that.mapMap); + return pigeonDeepEquals(aNullableBool, that.aNullableBool) + && pigeonDeepEquals(aNullableInt, that.aNullableInt) + && pigeonDeepEquals(aNullableInt64, that.aNullableInt64) + && pigeonDeepEquals(aNullableDouble, that.aNullableDouble) + && pigeonDeepEquals(aNullableByteArray, that.aNullableByteArray) + && pigeonDeepEquals(aNullable4ByteArray, that.aNullable4ByteArray) + && pigeonDeepEquals(aNullable8ByteArray, that.aNullable8ByteArray) + && pigeonDeepEquals(aNullableFloatArray, that.aNullableFloatArray) + && pigeonDeepEquals(aNullableEnum, that.aNullableEnum) + && pigeonDeepEquals(anotherNullableEnum, that.anotherNullableEnum) + && pigeonDeepEquals(aNullableString, that.aNullableString) + && pigeonDeepEquals(aNullableObject, that.aNullableObject) + && pigeonDeepEquals(list, that.list) + && pigeonDeepEquals(stringList, that.stringList) + && pigeonDeepEquals(intList, that.intList) + && pigeonDeepEquals(doubleList, that.doubleList) + && pigeonDeepEquals(boolList, that.boolList) + && pigeonDeepEquals(enumList, that.enumList) + && pigeonDeepEquals(objectList, that.objectList) + && pigeonDeepEquals(listList, that.listList) + && pigeonDeepEquals(mapList, that.mapList) + && pigeonDeepEquals(map, that.map) + && pigeonDeepEquals(stringMap, that.stringMap) + && pigeonDeepEquals(intMap, that.intMap) + && pigeonDeepEquals(enumMap, that.enumMap) + && pigeonDeepEquals(objectMap, that.objectMap) + && pigeonDeepEquals(listMap, that.listMap) + && pigeonDeepEquals(mapMap, that.mapMap); } @Override public int hashCode() { - int pigeonVar_result = - Objects.hash( - aNullableBool, - aNullableInt, - aNullableInt64, - aNullableDouble, - aNullableEnum, - anotherNullableEnum, - aNullableString, - aNullableObject, - list, - stringList, - intList, - doubleList, - boolList, - enumList, - objectList, - listList, - mapList, - map, - stringMap, - intMap, - enumMap, - objectMap, - listMap, - mapMap); - pigeonVar_result = 31 * pigeonVar_result + Arrays.hashCode(aNullableByteArray); - pigeonVar_result = 31 * pigeonVar_result + Arrays.hashCode(aNullable4ByteArray); - pigeonVar_result = 31 * pigeonVar_result + Arrays.hashCode(aNullable8ByteArray); - pigeonVar_result = 31 * pigeonVar_result + Arrays.hashCode(aNullableFloatArray); - return pigeonVar_result; + Object[] fields = + new Object[] { + getClass(), + aNullableBool, + aNullableInt, + aNullableInt64, + aNullableDouble, + aNullableByteArray, + aNullable4ByteArray, + aNullable8ByteArray, + aNullableFloatArray, + aNullableEnum, + anotherNullableEnum, + aNullableString, + aNullableObject, + list, + stringList, + intList, + doubleList, + boolList, + enumList, + objectList, + listList, + mapList, + map, + stringMap, + intMap, + enumMap, + objectMap, + listMap, + mapMap + }; + return pigeonDeepHashCode(fields); } public static final class Builder { @@ -2573,25 +2736,30 @@ public boolean equals(Object o) { return false; } AllClassesWrapper that = (AllClassesWrapper) o; - return allNullableTypes.equals(that.allNullableTypes) - && Objects.equals(allNullableTypesWithoutRecursion, that.allNullableTypesWithoutRecursion) - && Objects.equals(allTypes, that.allTypes) - && classList.equals(that.classList) - && Objects.equals(nullableClassList, that.nullableClassList) - && classMap.equals(that.classMap) - && Objects.equals(nullableClassMap, that.nullableClassMap); + return pigeonDeepEquals(allNullableTypes, that.allNullableTypes) + && pigeonDeepEquals( + allNullableTypesWithoutRecursion, that.allNullableTypesWithoutRecursion) + && pigeonDeepEquals(allTypes, that.allTypes) + && pigeonDeepEquals(classList, that.classList) + && pigeonDeepEquals(nullableClassList, that.nullableClassList) + && pigeonDeepEquals(classMap, that.classMap) + && pigeonDeepEquals(nullableClassMap, that.nullableClassMap); } @Override public int hashCode() { - return Objects.hash( - allNullableTypes, - allNullableTypesWithoutRecursion, - allTypes, - classList, - nullableClassList, - classMap, - nullableClassMap); + Object[] fields = + new Object[] { + getClass(), + allNullableTypes, + allNullableTypesWithoutRecursion, + allTypes, + classList, + nullableClassList, + classMap, + nullableClassMap + }; + return pigeonDeepHashCode(fields); } public static final class Builder { @@ -2728,12 +2896,13 @@ public boolean equals(Object o) { return false; } TestMessage that = (TestMessage) o; - return Objects.equals(testList, that.testList); + return pigeonDeepEquals(testList, that.testList); } @Override public int hashCode() { - return Objects.hash(testList); + Object[] fields = new Object[] {getClass(), testList}; + return pigeonDeepHashCode(fields); } public static final class Builder { @@ -2959,6 +3128,15 @@ public interface HostIntegrationCoreApi { /** Returns passed in int. */ @NonNull Long echoRequiredInt(@NonNull Long anInt); + /** Returns the result of platform-side equality check. */ + @NonNull + Boolean areAllNullableTypesEqual(@NonNull AllNullableTypes a, @NonNull AllNullableTypes b); + /** Returns the platform-side hash code for the given object. */ + @NonNull + Long getAllNullableTypesHash(@NonNull AllNullableTypes value); + /** Returns the platform-side hash code for the given object. */ + @NonNull + Long getAllNullableTypesWithoutRecursionHash(@NonNull AllNullableTypesWithoutRecursion value); /** Returns the passed object, to test serialization and deserialization. */ @Nullable AllNullableTypes echoAllNullableTypes(@Nullable AllNullableTypes everything); @@ -4120,6 +4298,83 @@ static void setUp( channel.setMessageHandler(null); } } + { + BasicMessageChannel channel = + new BasicMessageChannel<>( + binaryMessenger, + "dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi.areAllNullableTypesEqual" + + messageChannelSuffix, + getCodec()); + if (api != null) { + channel.setMessageHandler( + (message, reply) -> { + ArrayList wrapped = new ArrayList<>(); + ArrayList args = (ArrayList) message; + AllNullableTypes aArg = (AllNullableTypes) args.get(0); + AllNullableTypes bArg = (AllNullableTypes) args.get(1); + try { + Boolean output = api.areAllNullableTypesEqual(aArg, bArg); + wrapped.add(0, output); + } catch (Throwable exception) { + wrapped = wrapError(exception); + } + reply.reply(wrapped); + }); + } else { + channel.setMessageHandler(null); + } + } + { + BasicMessageChannel channel = + new BasicMessageChannel<>( + binaryMessenger, + "dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi.getAllNullableTypesHash" + + messageChannelSuffix, + getCodec()); + if (api != null) { + channel.setMessageHandler( + (message, reply) -> { + ArrayList wrapped = new ArrayList<>(); + ArrayList args = (ArrayList) message; + AllNullableTypes valueArg = (AllNullableTypes) args.get(0); + try { + Long output = api.getAllNullableTypesHash(valueArg); + wrapped.add(0, output); + } catch (Throwable exception) { + wrapped = wrapError(exception); + } + reply.reply(wrapped); + }); + } else { + channel.setMessageHandler(null); + } + } + { + BasicMessageChannel channel = + new BasicMessageChannel<>( + binaryMessenger, + "dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi.getAllNullableTypesWithoutRecursionHash" + + messageChannelSuffix, + getCodec()); + if (api != null) { + channel.setMessageHandler( + (message, reply) -> { + ArrayList wrapped = new ArrayList<>(); + ArrayList args = (ArrayList) message; + AllNullableTypesWithoutRecursion valueArg = + (AllNullableTypesWithoutRecursion) args.get(0); + try { + Long output = api.getAllNullableTypesWithoutRecursionHash(valueArg); + wrapped.add(0, output); + } catch (Throwable exception) { + wrapped = wrapError(exception); + } + reply.reply(wrapped); + }); + } else { + channel.setMessageHandler(null); + } + } { BasicMessageChannel channel = new BasicMessageChannel<>( diff --git a/packages/pigeon/platform_tests/alternate_language_test_plugin/android/src/test/java/com/example/alternate_language_test_plugin/AllDatatypesTest.java b/packages/pigeon/platform_tests/alternate_language_test_plugin/android/src/test/java/com/example/alternate_language_test_plugin/AllDatatypesTest.java index 1fb1e451dbbb..5671cc465163 100644 --- a/packages/pigeon/platform_tests/alternate_language_test_plugin/android/src/test/java/com/example/alternate_language_test_plugin/AllDatatypesTest.java +++ b/packages/pigeon/platform_tests/alternate_language_test_plugin/android/src/test/java/com/example/alternate_language_test_plugin/AllDatatypesTest.java @@ -266,4 +266,86 @@ public void error(Throwable error) { }); assertTrue(didCall[0]); } + + @Test + public void equalityWithNaN() { + AllNullableTypes withNaN = + new AllNullableTypes.Builder().setANullableDouble(Double.NaN).build(); + AllNullableTypes withAnotherNaN = + new AllNullableTypes.Builder().setANullableDouble(Double.NaN).build(); + assertEquals(withNaN, withAnotherNaN); + assertEquals(withNaN.hashCode(), withAnotherNaN.hashCode()); + } + + @Test + public void crossTypeEquality() { + AllNullableTypes a = new AllNullableTypes.Builder().setANullableInt(1L).build(); + CoreTests.AllNullableTypesWithoutRecursion b = + new CoreTests.AllNullableTypesWithoutRecursion.Builder().setANullableInt(1L).build(); + assertNotEquals(a, b); + assertNotEquals(b, a); + } + + @Test + public void zeroEquality() { + AllNullableTypes a = new AllNullableTypes.Builder().setANullableDouble(0.0).build(); + AllNullableTypes b = new AllNullableTypes.Builder().setANullableDouble(-0.0).build(); + + assertEquals(a, b); + assertEquals(a.hashCode(), b.hashCode()); + } + + @Test + public void nestedByteArrayEquality() { + byte[] data = new byte[] {1, 2, 3}; + List list1 = new ArrayList<>(); + list1.add(data); + AllNullableTypes a = new AllNullableTypes.Builder().setList(list1).build(); + + List list2 = new ArrayList<>(); + list2.add(new byte[] {1, 2, 3}); + AllNullableTypes b = new AllNullableTypes.Builder().setList(list2).build(); + + assertEquals(a, b); + assertEquals(a.hashCode(), b.hashCode()); + } + + @Test + public void nestedZeroListEquality() { + List list1 = new ArrayList<>(); + list1.add(0.0); + AllNullableTypes a = new AllNullableTypes.Builder().setDoubleList(list1).build(); + + List list2 = new ArrayList<>(); + list2.add(-0.0); + AllNullableTypes b = new AllNullableTypes.Builder().setDoubleList(list2).build(); + + assertEquals(a, b); + assertEquals(a.hashCode(), b.hashCode()); + } + + @Test + public void zeroMapKeyEquality() { + Map map1 = new HashMap<>(); + map1.put(0.0, "a"); + AllNullableTypes a = new AllNullableTypes.Builder().setMap(map1).build(); + + Map map2 = new HashMap<>(); + map2.put(-0.0, "a"); + AllNullableTypes b = new AllNullableTypes.Builder().setMap(map2).build(); + + assertEquals(a, b); + assertEquals(a.hashCode(), b.hashCode()); + } + + @Test + public void nestedZeroArrayEquality() { + AllNullableTypes a = + new AllNullableTypes.Builder().setANullableFloatArray(new double[] {0.0}).build(); + AllNullableTypes b = + new AllNullableTypes.Builder().setANullableFloatArray(new double[] {-0.0}).build(); + + assertEquals(a, b); + assertEquals(a.hashCode(), b.hashCode()); + } } diff --git a/packages/pigeon/platform_tests/alternate_language_test_plugin/darwin/alternate_language_test_plugin/Sources/alternate_language_test_plugin/AlternateLanguageTestPlugin.m b/packages/pigeon/platform_tests/alternate_language_test_plugin/darwin/alternate_language_test_plugin/Sources/alternate_language_test_plugin/AlternateLanguageTestPlugin.m index 1d494ba618ed..fdd0a0563ae5 100644 --- a/packages/pigeon/platform_tests/alternate_language_test_plugin/darwin/alternate_language_test_plugin/Sources/alternate_language_test_plugin/AlternateLanguageTestPlugin.m +++ b/packages/pigeon/platform_tests/alternate_language_test_plugin/darwin/alternate_language_test_plugin/Sources/alternate_language_test_plugin/AlternateLanguageTestPlugin.m @@ -201,6 +201,23 @@ - (nullable NSNumber *)echoRequiredInt:(NSInteger)anInt return @(anInt); } +- (nullable NSNumber *)areAllNullableTypesEqualA:(FLTAllNullableTypes *)a + b:(FLTAllNullableTypes *)b + error:(FlutterError *_Nullable *_Nonnull)error { + return @([a isEqual:b]); +} + +- (nullable NSNumber *)getAllNullableTypesHashValue:(FLTAllNullableTypes *)value + error:(FlutterError *_Nullable *_Nonnull)error { + return @([value hash]); +} + +- (nullable NSNumber *) + getAllNullableTypesWithoutRecursionHashValue:(FLTAllNullableTypesWithoutRecursion *)value + error:(FlutterError *_Nullable *_Nonnull)error { + return @([value hash]); +} + - (nullable NSString *)extractNestedNullableStringFrom:(FLTAllClassesWrapper *)wrapper error:(FlutterError *_Nullable *_Nonnull)error { return wrapper.allNullableTypes.aNullableString; diff --git a/packages/pigeon/platform_tests/alternate_language_test_plugin/darwin/alternate_language_test_plugin/Sources/alternate_language_test_plugin/CoreTests.gen.m b/packages/pigeon/platform_tests/alternate_language_test_plugin/darwin/alternate_language_test_plugin/Sources/alternate_language_test_plugin/CoreTests.gen.m index 38bd8f4a417f..7c114f8fa47b 100644 --- a/packages/pigeon/platform_tests/alternate_language_test_plugin/darwin/alternate_language_test_plugin/Sources/alternate_language_test_plugin/CoreTests.gen.m +++ b/packages/pigeon/platform_tests/alternate_language_test_plugin/darwin/alternate_language_test_plugin/Sources/alternate_language_test_plugin/CoreTests.gen.m @@ -13,6 +13,97 @@ @import Flutter; #endif +static BOOL __attribute__((unused)) FLTPigeonDeepEquals(id _Nullable a, id _Nullable b) { + if (a == b) { + return YES; + } + if (a == nil) { + return b == [NSNull null]; + } + if (b == nil) { + return a == [NSNull null]; + } + if ([a isKindOfClass:[NSNumber class]] && [b isKindOfClass:[NSNumber class]]) { + return + [a isEqual:b] || (isnan([(NSNumber *)a doubleValue]) && isnan([(NSNumber *)b doubleValue])); + } + if ([a isKindOfClass:[NSArray class]] && [b isKindOfClass:[NSArray class]]) { + NSArray *arrayA = (NSArray *)a; + NSArray *arrayB = (NSArray *)b; + if (arrayA.count != arrayB.count) { + return NO; + } + for (NSUInteger i = 0; i < arrayA.count; i++) { + if (!FLTPigeonDeepEquals(arrayA[i], arrayB[i])) { + return NO; + } + } + return YES; + } + if ([a isKindOfClass:[NSDictionary class]] && [b isKindOfClass:[NSDictionary class]]) { + NSDictionary *dictA = (NSDictionary *)a; + NSDictionary *dictB = (NSDictionary *)b; + if (dictA.count != dictB.count) { + return NO; + } + for (id keyA in dictA) { + id valueA = dictA[keyA]; + BOOL found = NO; + for (id keyB in dictB) { + if (FLTPigeonDeepEquals(keyA, keyB)) { + id valueB = dictB[keyB]; + if (FLTPigeonDeepEquals(valueA, valueB)) { + found = YES; + break; + } else { + return NO; + } + } + } + if (!found) { + return NO; + } + } + return YES; + } + return [a isEqual:b]; +} + +static NSUInteger __attribute__((unused)) FLTPigeonDeepHash(id _Nullable value) { + if (value == nil || value == (id)[NSNull null]) { + return 0; + } + if ([value isKindOfClass:[NSNumber class]]) { + NSNumber *n = (NSNumber *)value; + double d = n.doubleValue; + if (isnan(d)) { + // Normalize NaN to a consistent hash. + return (NSUInteger)0x7FF8000000000000; + } + if (d == 0.0) { + // Normalize -0.0 to 0.0 so they have the same hash code. + d = 0.0; + } + return @(d).hash; + } + if ([value isKindOfClass:[NSArray class]]) { + NSUInteger result = 1; + for (id item in (NSArray *)value) { + result = result * 31 + FLTPigeonDeepHash(item); + } + return result; + } + if ([value isKindOfClass:[NSDictionary class]]) { + NSUInteger result = 0; + NSDictionary *dict = (NSDictionary *)value; + for (id key in dict) { + result += ((FLTPigeonDeepHash(key) * 31) ^ FLTPigeonDeepHash(dict[key])); + } + return result; + } + return [value hash]; +} + static NSArray *wrapResult(id result, FlutterError *error) { if (error) { return @[ @@ -111,6 +202,22 @@ + (nullable FLTUnusedClass *)nullableFromList:(NSArray *)list { self.aField ?: [NSNull null], ]; } +- (BOOL)isEqual:(id)object { + if (self == object) { + return YES; + } + if (![object isKindOfClass:[self class]]) { + return NO; + } + FLTUnusedClass *other = (FLTUnusedClass *)object; + return FLTPigeonDeepEquals(self.aField, other.aField); +} + +- (NSUInteger)hash { + NSUInteger result = [self class].hash; + result = result * 31 + FLTPigeonDeepHash(self.aField); + return result; +} @end @implementation FLTAllTypes @@ -242,6 +349,74 @@ + (nullable FLTAllTypes *)nullableFromList:(NSArray *)list { self.mapMap ?: [NSNull null], ]; } +- (BOOL)isEqual:(id)object { + if (self == object) { + return YES; + } + if (![object isKindOfClass:[self class]]) { + return NO; + } + FLTAllTypes *other = (FLTAllTypes *)object; + return self.aBool == other.aBool && self.anInt == other.anInt && self.anInt64 == other.anInt64 && + (self.aDouble == other.aDouble || (isnan(self.aDouble) && isnan(other.aDouble))) && + FLTPigeonDeepEquals(self.aByteArray, other.aByteArray) && + FLTPigeonDeepEquals(self.a4ByteArray, other.a4ByteArray) && + FLTPigeonDeepEquals(self.a8ByteArray, other.a8ByteArray) && + FLTPigeonDeepEquals(self.aFloatArray, other.aFloatArray) && self.anEnum == other.anEnum && + self.anotherEnum == other.anotherEnum && + FLTPigeonDeepEquals(self.aString, other.aString) && + FLTPigeonDeepEquals(self.anObject, other.anObject) && + FLTPigeonDeepEquals(self.list, other.list) && + FLTPigeonDeepEquals(self.stringList, other.stringList) && + FLTPigeonDeepEquals(self.intList, other.intList) && + FLTPigeonDeepEquals(self.doubleList, other.doubleList) && + FLTPigeonDeepEquals(self.boolList, other.boolList) && + FLTPigeonDeepEquals(self.enumList, other.enumList) && + FLTPigeonDeepEquals(self.objectList, other.objectList) && + FLTPigeonDeepEquals(self.listList, other.listList) && + FLTPigeonDeepEquals(self.mapList, other.mapList) && + FLTPigeonDeepEquals(self.map, other.map) && + FLTPigeonDeepEquals(self.stringMap, other.stringMap) && + FLTPigeonDeepEquals(self.intMap, other.intMap) && + FLTPigeonDeepEquals(self.enumMap, other.enumMap) && + FLTPigeonDeepEquals(self.objectMap, other.objectMap) && + FLTPigeonDeepEquals(self.listMap, other.listMap) && + FLTPigeonDeepEquals(self.mapMap, other.mapMap); +} + +- (NSUInteger)hash { + NSUInteger result = [self class].hash; + result = result * 31 + @(self.aBool).hash; + result = result * 31 + @(self.anInt).hash; + result = result * 31 + @(self.anInt64).hash; + result = + result * 31 + (isnan(self.aDouble) ? (NSUInteger)0x7FF8000000000000 : @(self.aDouble).hash); + result = result * 31 + FLTPigeonDeepHash(self.aByteArray); + result = result * 31 + FLTPigeonDeepHash(self.a4ByteArray); + result = result * 31 + FLTPigeonDeepHash(self.a8ByteArray); + result = result * 31 + FLTPigeonDeepHash(self.aFloatArray); + result = result * 31 + @(self.anEnum).hash; + result = result * 31 + @(self.anotherEnum).hash; + result = result * 31 + FLTPigeonDeepHash(self.aString); + result = result * 31 + FLTPigeonDeepHash(self.anObject); + result = result * 31 + FLTPigeonDeepHash(self.list); + result = result * 31 + FLTPigeonDeepHash(self.stringList); + result = result * 31 + FLTPigeonDeepHash(self.intList); + result = result * 31 + FLTPigeonDeepHash(self.doubleList); + result = result * 31 + FLTPigeonDeepHash(self.boolList); + result = result * 31 + FLTPigeonDeepHash(self.enumList); + result = result * 31 + FLTPigeonDeepHash(self.objectList); + result = result * 31 + FLTPigeonDeepHash(self.listList); + result = result * 31 + FLTPigeonDeepHash(self.mapList); + result = result * 31 + FLTPigeonDeepHash(self.map); + result = result * 31 + FLTPigeonDeepHash(self.stringMap); + result = result * 31 + FLTPigeonDeepHash(self.intMap); + result = result * 31 + FLTPigeonDeepHash(self.enumMap); + result = result * 31 + FLTPigeonDeepHash(self.objectMap); + result = result * 31 + FLTPigeonDeepHash(self.listMap); + result = result * 31 + FLTPigeonDeepHash(self.mapMap); + return result; +} @end @implementation FLTAllNullableTypes @@ -385,6 +560,82 @@ + (nullable FLTAllNullableTypes *)nullableFromList:(NSArray *)list { self.recursiveClassMap ?: [NSNull null], ]; } +- (BOOL)isEqual:(id)object { + if (self == object) { + return YES; + } + if (![object isKindOfClass:[self class]]) { + return NO; + } + FLTAllNullableTypes *other = (FLTAllNullableTypes *)object; + return FLTPigeonDeepEquals(self.aNullableBool, other.aNullableBool) && + FLTPigeonDeepEquals(self.aNullableInt, other.aNullableInt) && + FLTPigeonDeepEquals(self.aNullableInt64, other.aNullableInt64) && + FLTPigeonDeepEquals(self.aNullableDouble, other.aNullableDouble) && + FLTPigeonDeepEquals(self.aNullableByteArray, other.aNullableByteArray) && + FLTPigeonDeepEquals(self.aNullable4ByteArray, other.aNullable4ByteArray) && + FLTPigeonDeepEquals(self.aNullable8ByteArray, other.aNullable8ByteArray) && + FLTPigeonDeepEquals(self.aNullableFloatArray, other.aNullableFloatArray) && + FLTPigeonDeepEquals(self.aNullableEnum, other.aNullableEnum) && + FLTPigeonDeepEquals(self.anotherNullableEnum, other.anotherNullableEnum) && + FLTPigeonDeepEquals(self.aNullableString, other.aNullableString) && + FLTPigeonDeepEquals(self.aNullableObject, other.aNullableObject) && + FLTPigeonDeepEquals(self.allNullableTypes, other.allNullableTypes) && + FLTPigeonDeepEquals(self.list, other.list) && + FLTPigeonDeepEquals(self.stringList, other.stringList) && + FLTPigeonDeepEquals(self.intList, other.intList) && + FLTPigeonDeepEquals(self.doubleList, other.doubleList) && + FLTPigeonDeepEquals(self.boolList, other.boolList) && + FLTPigeonDeepEquals(self.enumList, other.enumList) && + FLTPigeonDeepEquals(self.objectList, other.objectList) && + FLTPigeonDeepEquals(self.listList, other.listList) && + FLTPigeonDeepEquals(self.mapList, other.mapList) && + FLTPigeonDeepEquals(self.recursiveClassList, other.recursiveClassList) && + FLTPigeonDeepEquals(self.map, other.map) && + FLTPigeonDeepEquals(self.stringMap, other.stringMap) && + FLTPigeonDeepEquals(self.intMap, other.intMap) && + FLTPigeonDeepEquals(self.enumMap, other.enumMap) && + FLTPigeonDeepEquals(self.objectMap, other.objectMap) && + FLTPigeonDeepEquals(self.listMap, other.listMap) && + FLTPigeonDeepEquals(self.mapMap, other.mapMap) && + FLTPigeonDeepEquals(self.recursiveClassMap, other.recursiveClassMap); +} + +- (NSUInteger)hash { + NSUInteger result = [self class].hash; + result = result * 31 + FLTPigeonDeepHash(self.aNullableBool); + result = result * 31 + FLTPigeonDeepHash(self.aNullableInt); + result = result * 31 + FLTPigeonDeepHash(self.aNullableInt64); + result = result * 31 + FLTPigeonDeepHash(self.aNullableDouble); + result = result * 31 + FLTPigeonDeepHash(self.aNullableByteArray); + result = result * 31 + FLTPigeonDeepHash(self.aNullable4ByteArray); + result = result * 31 + FLTPigeonDeepHash(self.aNullable8ByteArray); + result = result * 31 + FLTPigeonDeepHash(self.aNullableFloatArray); + result = result * 31 + FLTPigeonDeepHash(self.aNullableEnum); + result = result * 31 + FLTPigeonDeepHash(self.anotherNullableEnum); + result = result * 31 + FLTPigeonDeepHash(self.aNullableString); + result = result * 31 + FLTPigeonDeepHash(self.aNullableObject); + result = result * 31 + FLTPigeonDeepHash(self.allNullableTypes); + result = result * 31 + FLTPigeonDeepHash(self.list); + result = result * 31 + FLTPigeonDeepHash(self.stringList); + result = result * 31 + FLTPigeonDeepHash(self.intList); + result = result * 31 + FLTPigeonDeepHash(self.doubleList); + result = result * 31 + FLTPigeonDeepHash(self.boolList); + result = result * 31 + FLTPigeonDeepHash(self.enumList); + result = result * 31 + FLTPigeonDeepHash(self.objectList); + result = result * 31 + FLTPigeonDeepHash(self.listList); + result = result * 31 + FLTPigeonDeepHash(self.mapList); + result = result * 31 + FLTPigeonDeepHash(self.recursiveClassList); + result = result * 31 + FLTPigeonDeepHash(self.map); + result = result * 31 + FLTPigeonDeepHash(self.stringMap); + result = result * 31 + FLTPigeonDeepHash(self.intMap); + result = result * 31 + FLTPigeonDeepHash(self.enumMap); + result = result * 31 + FLTPigeonDeepHash(self.objectMap); + result = result * 31 + FLTPigeonDeepHash(self.listMap); + result = result * 31 + FLTPigeonDeepHash(self.mapMap); + result = result * 31 + FLTPigeonDeepHash(self.recursiveClassMap); + return result; +} @end @implementation FLTAllNullableTypesWithoutRecursion @@ -517,6 +768,76 @@ + (nullable FLTAllNullableTypesWithoutRecursion *)nullableFromList:(NSArray self.mapMap ?: [NSNull null], ]; } +- (BOOL)isEqual:(id)object { + if (self == object) { + return YES; + } + if (![object isKindOfClass:[self class]]) { + return NO; + } + FLTAllNullableTypesWithoutRecursion *other = (FLTAllNullableTypesWithoutRecursion *)object; + return FLTPigeonDeepEquals(self.aNullableBool, other.aNullableBool) && + FLTPigeonDeepEquals(self.aNullableInt, other.aNullableInt) && + FLTPigeonDeepEquals(self.aNullableInt64, other.aNullableInt64) && + FLTPigeonDeepEquals(self.aNullableDouble, other.aNullableDouble) && + FLTPigeonDeepEquals(self.aNullableByteArray, other.aNullableByteArray) && + FLTPigeonDeepEquals(self.aNullable4ByteArray, other.aNullable4ByteArray) && + FLTPigeonDeepEquals(self.aNullable8ByteArray, other.aNullable8ByteArray) && + FLTPigeonDeepEquals(self.aNullableFloatArray, other.aNullableFloatArray) && + FLTPigeonDeepEquals(self.aNullableEnum, other.aNullableEnum) && + FLTPigeonDeepEquals(self.anotherNullableEnum, other.anotherNullableEnum) && + FLTPigeonDeepEquals(self.aNullableString, other.aNullableString) && + FLTPigeonDeepEquals(self.aNullableObject, other.aNullableObject) && + FLTPigeonDeepEquals(self.list, other.list) && + FLTPigeonDeepEquals(self.stringList, other.stringList) && + FLTPigeonDeepEquals(self.intList, other.intList) && + FLTPigeonDeepEquals(self.doubleList, other.doubleList) && + FLTPigeonDeepEquals(self.boolList, other.boolList) && + FLTPigeonDeepEquals(self.enumList, other.enumList) && + FLTPigeonDeepEquals(self.objectList, other.objectList) && + FLTPigeonDeepEquals(self.listList, other.listList) && + FLTPigeonDeepEquals(self.mapList, other.mapList) && + FLTPigeonDeepEquals(self.map, other.map) && + FLTPigeonDeepEquals(self.stringMap, other.stringMap) && + FLTPigeonDeepEquals(self.intMap, other.intMap) && + FLTPigeonDeepEquals(self.enumMap, other.enumMap) && + FLTPigeonDeepEquals(self.objectMap, other.objectMap) && + FLTPigeonDeepEquals(self.listMap, other.listMap) && + FLTPigeonDeepEquals(self.mapMap, other.mapMap); +} + +- (NSUInteger)hash { + NSUInteger result = [self class].hash; + result = result * 31 + FLTPigeonDeepHash(self.aNullableBool); + result = result * 31 + FLTPigeonDeepHash(self.aNullableInt); + result = result * 31 + FLTPigeonDeepHash(self.aNullableInt64); + result = result * 31 + FLTPigeonDeepHash(self.aNullableDouble); + result = result * 31 + FLTPigeonDeepHash(self.aNullableByteArray); + result = result * 31 + FLTPigeonDeepHash(self.aNullable4ByteArray); + result = result * 31 + FLTPigeonDeepHash(self.aNullable8ByteArray); + result = result * 31 + FLTPigeonDeepHash(self.aNullableFloatArray); + result = result * 31 + FLTPigeonDeepHash(self.aNullableEnum); + result = result * 31 + FLTPigeonDeepHash(self.anotherNullableEnum); + result = result * 31 + FLTPigeonDeepHash(self.aNullableString); + result = result * 31 + FLTPigeonDeepHash(self.aNullableObject); + result = result * 31 + FLTPigeonDeepHash(self.list); + result = result * 31 + FLTPigeonDeepHash(self.stringList); + result = result * 31 + FLTPigeonDeepHash(self.intList); + result = result * 31 + FLTPigeonDeepHash(self.doubleList); + result = result * 31 + FLTPigeonDeepHash(self.boolList); + result = result * 31 + FLTPigeonDeepHash(self.enumList); + result = result * 31 + FLTPigeonDeepHash(self.objectList); + result = result * 31 + FLTPigeonDeepHash(self.listList); + result = result * 31 + FLTPigeonDeepHash(self.mapList); + result = result * 31 + FLTPigeonDeepHash(self.map); + result = result * 31 + FLTPigeonDeepHash(self.stringMap); + result = result * 31 + FLTPigeonDeepHash(self.intMap); + result = result * 31 + FLTPigeonDeepHash(self.enumMap); + result = result * 31 + FLTPigeonDeepHash(self.objectMap); + result = result * 31 + FLTPigeonDeepHash(self.listMap); + result = result * 31 + FLTPigeonDeepHash(self.mapMap); + return result; +} @end @implementation FLTAllClassesWrapper @@ -567,6 +888,35 @@ + (nullable FLTAllClassesWrapper *)nullableFromList:(NSArray *)list { self.nullableClassMap ?: [NSNull null], ]; } +- (BOOL)isEqual:(id)object { + if (self == object) { + return YES; + } + if (![object isKindOfClass:[self class]]) { + return NO; + } + FLTAllClassesWrapper *other = (FLTAllClassesWrapper *)object; + return FLTPigeonDeepEquals(self.allNullableTypes, other.allNullableTypes) && + FLTPigeonDeepEquals(self.allNullableTypesWithoutRecursion, + other.allNullableTypesWithoutRecursion) && + FLTPigeonDeepEquals(self.allTypes, other.allTypes) && + FLTPigeonDeepEquals(self.classList, other.classList) && + FLTPigeonDeepEquals(self.nullableClassList, other.nullableClassList) && + FLTPigeonDeepEquals(self.classMap, other.classMap) && + FLTPigeonDeepEquals(self.nullableClassMap, other.nullableClassMap); +} + +- (NSUInteger)hash { + NSUInteger result = [self class].hash; + result = result * 31 + FLTPigeonDeepHash(self.allNullableTypes); + result = result * 31 + FLTPigeonDeepHash(self.allNullableTypesWithoutRecursion); + result = result * 31 + FLTPigeonDeepHash(self.allTypes); + result = result * 31 + FLTPigeonDeepHash(self.classList); + result = result * 31 + FLTPigeonDeepHash(self.nullableClassList); + result = result * 31 + FLTPigeonDeepHash(self.classMap); + result = result * 31 + FLTPigeonDeepHash(self.nullableClassMap); + return result; +} @end @implementation FLTTestMessage @@ -588,6 +938,22 @@ + (nullable FLTTestMessage *)nullableFromList:(NSArray *)list { self.testList ?: [NSNull null], ]; } +- (BOOL)isEqual:(id)object { + if (self == object) { + return YES; + } + if (![object isKindOfClass:[self class]]) { + return NO; + } + FLTTestMessage *other = (FLTTestMessage *)object; + return FLTPigeonDeepEquals(self.testList, other.testList); +} + +- (NSUInteger)hash { + NSUInteger result = [self class].hash; + result = result * 31 + FLTPigeonDeepHash(self.testList); + return result; +} @end @interface FLTCoreTestsPigeonCodecReader : FlutterStandardReader @@ -1474,6 +1840,88 @@ void SetUpFLTHostIntegrationCoreApiWithSuffix(id binaryM [channel setMessageHandler:nil]; } } + /// Returns the result of platform-side equality check. + { + FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] + initWithName:[NSString + stringWithFormat:@"%@%@", + @"dev.flutter.pigeon.pigeon_integration_tests." + @"HostIntegrationCoreApi.areAllNullableTypesEqual", + messageChannelSuffix] + binaryMessenger:binaryMessenger + codec:FLTGetCoreTestsCodec()]; + if (api) { + NSCAssert([api respondsToSelector:@selector(areAllNullableTypesEqualA:b:error:)], + @"FLTHostIntegrationCoreApi api (%@) doesn't respond to " + @"@selector(areAllNullableTypesEqualA:b:error:)", + api); + [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { + NSArray *args = message; + FLTAllNullableTypes *arg_a = GetNullableObjectAtIndex(args, 0); + FLTAllNullableTypes *arg_b = GetNullableObjectAtIndex(args, 1); + FlutterError *error; + NSNumber *output = [api areAllNullableTypesEqualA:arg_a b:arg_b error:&error]; + callback(wrapResult(output, error)); + }]; + } else { + [channel setMessageHandler:nil]; + } + } + /// Returns the platform-side hash code for the given object. + { + FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] + initWithName:[NSString + stringWithFormat:@"%@%@", + @"dev.flutter.pigeon.pigeon_integration_tests." + @"HostIntegrationCoreApi.getAllNullableTypesHash", + messageChannelSuffix] + binaryMessenger:binaryMessenger + codec:FLTGetCoreTestsCodec()]; + if (api) { + NSCAssert([api respondsToSelector:@selector(getAllNullableTypesHashValue:error:)], + @"FLTHostIntegrationCoreApi api (%@) doesn't respond to " + @"@selector(getAllNullableTypesHashValue:error:)", + api); + [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { + NSArray *args = message; + FLTAllNullableTypes *arg_value = GetNullableObjectAtIndex(args, 0); + FlutterError *error; + NSNumber *output = [api getAllNullableTypesHashValue:arg_value error:&error]; + callback(wrapResult(output, error)); + }]; + } else { + [channel setMessageHandler:nil]; + } + } + /// Returns the platform-side hash code for the given object. + { + FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] + initWithName:[NSString + stringWithFormat: + @"%@%@", + @"dev.flutter.pigeon.pigeon_integration_tests." + @"HostIntegrationCoreApi.getAllNullableTypesWithoutRecursionHash", + messageChannelSuffix] + binaryMessenger:binaryMessenger + codec:FLTGetCoreTestsCodec()]; + if (api) { + NSCAssert([api respondsToSelector:@selector(getAllNullableTypesWithoutRecursionHashValue: + error:)], + @"FLTHostIntegrationCoreApi api (%@) doesn't respond to " + @"@selector(getAllNullableTypesWithoutRecursionHashValue:error:)", + api); + [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { + NSArray *args = message; + FLTAllNullableTypesWithoutRecursion *arg_value = GetNullableObjectAtIndex(args, 0); + FlutterError *error; + NSNumber *output = [api getAllNullableTypesWithoutRecursionHashValue:arg_value + error:&error]; + callback(wrapResult(output, error)); + }]; + } else { + [channel setMessageHandler:nil]; + } + } /// Returns the passed object, to test serialization and deserialization. { FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] diff --git a/packages/pigeon/platform_tests/alternate_language_test_plugin/darwin/alternate_language_test_plugin/Sources/alternate_language_test_plugin/include/alternate_language_test_plugin/CoreTests.gen.h b/packages/pigeon/platform_tests/alternate_language_test_plugin/darwin/alternate_language_test_plugin/Sources/alternate_language_test_plugin/include/alternate_language_test_plugin/CoreTests.gen.h index 83f632d43b3b..2b620a11104a 100644 --- a/packages/pigeon/platform_tests/alternate_language_test_plugin/darwin/alternate_language_test_plugin/Sources/alternate_language_test_plugin/include/alternate_language_test_plugin/CoreTests.gen.h +++ b/packages/pigeon/platform_tests/alternate_language_test_plugin/darwin/alternate_language_test_plugin/Sources/alternate_language_test_plugin/include/alternate_language_test_plugin/CoreTests.gen.h @@ -438,6 +438,23 @@ NSObject *FLTGetCoreTestsCodec(void); /// @return `nil` only when `error != nil`. - (nullable NSNumber *)echoRequiredInt:(NSInteger)anInt error:(FlutterError *_Nullable *_Nonnull)error; +/// Returns the result of platform-side equality check. +/// +/// @return `nil` only when `error != nil`. +- (nullable NSNumber *)areAllNullableTypesEqualA:(FLTAllNullableTypes *)a + b:(FLTAllNullableTypes *)b + error:(FlutterError *_Nullable *_Nonnull)error; +/// Returns the platform-side hash code for the given object. +/// +/// @return `nil` only when `error != nil`. +- (nullable NSNumber *)getAllNullableTypesHashValue:(FLTAllNullableTypes *)value + error:(FlutterError *_Nullable *_Nonnull)error; +/// Returns the platform-side hash code for the given object. +/// +/// @return `nil` only when `error != nil`. +- (nullable NSNumber *) + getAllNullableTypesWithoutRecursionHashValue:(FLTAllNullableTypesWithoutRecursion *)value + error:(FlutterError *_Nullable *_Nonnull)error; /// Returns the passed object, to test serialization and deserialization. - (nullable FLTAllNullableTypes *)echoAllNullableTypes:(nullable FLTAllNullableTypes *)everything error:(FlutterError *_Nullable *_Nonnull)error; diff --git a/packages/pigeon/platform_tests/alternate_language_test_plugin/example/ios/RunnerTests/AllDatatypesTest.m b/packages/pigeon/platform_tests/alternate_language_test_plugin/example/ios/RunnerTests/AllDatatypesTest.m index ddef818e0c5a..4e5b5b196f5a 100644 --- a/packages/pigeon/platform_tests/alternate_language_test_plugin/example/ios/RunnerTests/AllDatatypesTest.m +++ b/packages/pigeon/platform_tests/alternate_language_test_plugin/example/ios/RunnerTests/AllDatatypesTest.m @@ -114,8 +114,125 @@ - (void)testAllEquals { [self waitForExpectations:@[ expectation ] timeout:1.0]; } -- (void)unusedClassesExist { - XCTAssert([[FLTUnusedClass alloc] init] != nil); +- (void)testEquality { + FLTAllNullableTypes *everything1 = [[FLTAllNullableTypes alloc] init]; + everything1.aNullableBool = @NO; + everything1.aNullableInt = @(1); + everything1.aNullableString = @"123"; + + FLTAllNullableTypes *everything2 = [[FLTAllNullableTypes alloc] init]; + everything2.aNullableBool = @NO; + everything2.aNullableInt = @(1); + everything2.aNullableString = @"123"; + + FLTAllNullableTypes *everything3 = [[FLTAllNullableTypes alloc] init]; + everything3.aNullableBool = @YES; + + XCTAssertEqualObjects(everything1, everything2); + XCTAssertNotEqualObjects(everything1, everything3); + XCTAssertEqual(everything1.hash, everything2.hash); +} + +- (void)testNaNEquality { + FLTAllNullableTypes *everything1 = [[FLTAllNullableTypes alloc] init]; + everything1.aNullableDouble = @(NAN); + + FLTAllNullableTypes *everything2 = [[FLTAllNullableTypes alloc] init]; + everything2.aNullableDouble = @(NAN); + + XCTAssertEqualObjects(everything1, everything2); + XCTAssertEqual(everything1.hash, everything2.hash); +} + +- (void)testCrossTypeEquality { + FLTAllNullableTypes *a = [[FLTAllNullableTypes alloc] init]; + a.aNullableInt = @(1); + + FLTAllNullableTypesWithoutRecursion *b = [[FLTAllNullableTypesWithoutRecursion alloc] init]; + b.aNullableInt = @(1); + + XCTAssertNotEqualObjects(a, b); + XCTAssertNotEqualObjects(b, a); +} + +- (void)testZeroEquality { + FLTAllNullableTypes *a = [[FLTAllNullableTypes alloc] init]; + a.aNullableDouble = @(0.0); + + FLTAllNullableTypes *b = [[FLTAllNullableTypes alloc] init]; + b.aNullableDouble = @(-0.0); + + XCTAssertEqualObjects(a, b); + XCTAssertEqual(a.hash, b.hash); +} + +- (void)testNestedNaNEquality { + FLTAllNullableTypes *a = [[FLTAllNullableTypes alloc] init]; + a.aNullableDouble = @(nan("")); + a.doubleList = @[ @(nan("")) ]; + + FLTAllNullableTypes *b = [[FLTAllNullableTypes alloc] init]; + b.aNullableDouble = @(nan("")); + b.doubleList = @[ @(nan("")) ]; + + // If this fails, Objective-C needs a deepEquals helper too. + XCTAssertEqualObjects(a, b); + XCTAssertEqual(a.hash, b.hash); +} + +- (void)testNestedZeroListEquality { + FLTAllNullableTypes *a = [[FLTAllNullableTypes alloc] init]; + a.doubleList = @[ @(0.0) ]; + + FLTAllNullableTypes *b = [[FLTAllNullableTypes alloc] init]; + b.doubleList = @[ @(-0.0) ]; + + XCTAssertEqualObjects(a, b); + XCTAssertEqual(a.hash, b.hash); +} + +- (void)testZeroMapKeyEquality { + FLTAllNullableTypes *a = [[FLTAllNullableTypes alloc] init]; + a.map = @{@(0.0) : @"a"}; + + FLTAllNullableTypes *b = [[FLTAllNullableTypes alloc] init]; + b.map = @{@(-0.0) : @"a"}; + + XCTAssertEqualObjects(a, b); + XCTAssertEqual(a.hash, b.hash); +} + +- (void)testZeroMapValueEquality { + FLTAllNullableTypes *a = [[FLTAllNullableTypes alloc] init]; + a.map = @{@"a" : @(0.0)}; + + FLTAllNullableTypes *b = [[FLTAllNullableTypes alloc] init]; + b.map = @{@"a" : @(-0.0)}; + + XCTAssertEqualObjects(a, b); + XCTAssertEqual(a.hash, b.hash); +} + +- (void)testNSNullListEquality { + FLTAllNullableTypes *a = [[FLTAllNullableTypes alloc] init]; + a.list = @[ [NSNull null] ]; + + FLTAllNullableTypes *b = [[FLTAllNullableTypes alloc] init]; + b.list = @[ [NSNull null] ]; + + XCTAssertEqualObjects(a, b); + XCTAssertEqual(a.hash, b.hash); +} + +- (void)testNSNullPropertyEquality { + FLTAllNullableTypes *a = [[FLTAllNullableTypes alloc] init]; + a.aNullableObject = [NSNull null]; + + FLTAllNullableTypes *b = [[FLTAllNullableTypes alloc] init]; + b.aNullableObject = nil; + + XCTAssertEqualObjects(a, b); + XCTAssertEqual(a.hash, b.hash); } @end diff --git a/packages/pigeon/platform_tests/alternate_language_test_plugin/example/ios/RunnerTests/NonNullFieldsTest.m b/packages/pigeon/platform_tests/alternate_language_test_plugin/example/ios/RunnerTests/NonNullFieldsTest.m index 573bb994f91c..cd0369996a01 100644 --- a/packages/pigeon/platform_tests/alternate_language_test_plugin/example/ios/RunnerTests/NonNullFieldsTest.m +++ b/packages/pigeon/platform_tests/alternate_language_test_plugin/example/ios/RunnerTests/NonNullFieldsTest.m @@ -22,4 +22,14 @@ - (void)testMake { XCTAssertEqualObjects(@"hello", request.query); } +- (void)testEquality { + NonNullFieldSearchRequest *request1 = [NonNullFieldSearchRequest makeWithQuery:@"hello"]; + NonNullFieldSearchRequest *request2 = [NonNullFieldSearchRequest makeWithQuery:@"hello"]; + NonNullFieldSearchRequest *request3 = [NonNullFieldSearchRequest makeWithQuery:@"world"]; + + XCTAssertEqualObjects(request1, request2); + XCTAssertNotEqualObjects(request1, request3); + XCTAssertEqual(request1.hash, request2.hash); +} + @end diff --git a/packages/pigeon/platform_tests/shared_test_plugin_code/lib/integration_tests.dart b/packages/pigeon/platform_tests/shared_test_plugin_code/lib/integration_tests.dart index aedbf2da1644..9ed43123a701 100644 --- a/packages/pigeon/platform_tests/shared_test_plugin_code/lib/integration_tests.dart +++ b/packages/pigeon/platform_tests/shared_test_plugin_code/lib/integration_tests.dart @@ -1024,6 +1024,171 @@ void runPigeonIntegrationTests(TargetGenerator targetGenerator) { final String? receivedNullString = await api.echoNamedNullableString(); expect(receivedNullString, null); }); + + testWidgets('Signed zero equality', (WidgetTester _) async { + final api = HostIntegrationCoreApi(); + + final a = AllNullableTypes(aNullableDouble: 0.0); + final b = AllNullableTypes(aNullableDouble: -0.0); + + expect(await api.areAllNullableTypesEqual(a, b), isTrue); + }); + + testWidgets('Signed zero hashing', (WidgetTester _) async { + final api = HostIntegrationCoreApi(); + + final a = AllNullableTypes(aNullableDouble: 0.0); + final b = AllNullableTypes(aNullableDouble: -0.0); + + final int hashA = await api.getAllNullableTypesHash(a); + final int hashB = await api.getAllNullableTypesHash(b); + expect( + hashA, + hashB, + reason: 'Hash codes for 0.0 and -0.0 should be equal', + ); + }); + + testWidgets('NaN equality', (WidgetTester _) async { + final api = HostIntegrationCoreApi(); + + final a = AllNullableTypes(aNullableDouble: double.nan); + final b = AllNullableTypes(aNullableDouble: double.nan); + + expect(await api.areAllNullableTypesEqual(a, b), isTrue); + }); + + testWidgets('NaN hashing', (WidgetTester _) async { + final api = HostIntegrationCoreApi(); + + final a = AllNullableTypes(aNullableDouble: double.nan); + final b = AllNullableTypes(aNullableDouble: double.nan); + + final int hashA = await api.getAllNullableTypesHash(a); + final int hashB = await api.getAllNullableTypesHash(b); + expect(hashA, hashB, reason: 'Hash codes for two NaNs should be equal'); + }); + + testWidgets('Collection equality with signed zero and NaN', ( + WidgetTester _, + ) async { + final api = HostIntegrationCoreApi(); + + final a = AllNullableTypes( + doubleList: [0.0, double.nan], + stringMap: {'k': 'v', 'n': null}, + ); + final b = AllNullableTypes( + doubleList: [-0.0, double.nan], + stringMap: {'n': null, 'k': 'v'}, + ); + + expect(await api.areAllNullableTypesEqual(a, b), isTrue); + }); + + testWidgets('Collection hashing with signed zero and NaN', ( + WidgetTester _, + ) async { + final api = HostIntegrationCoreApi(); + + final a = AllNullableTypes( + doubleList: [0.0, double.nan], + stringMap: {'k': 'v', 'n': null}, + ); + final b = AllNullableTypes( + doubleList: [-0.0, double.nan], + stringMap: {'n': null, 'k': 'v'}, + ); + + expect( + await api.getAllNullableTypesHash(a), + await api.getAllNullableTypesHash(b), + ); + }); + + testWidgets('Collection hashing with null/NSNull', (WidgetTester _) async { + final api = HostIntegrationCoreApi(); + + final a = AllNullableTypes( + list: [null], + stringMap: {'k': null}, + ); + final b = AllNullableTypes( + list: [null], + stringMap: {'k': null}, + ); + + // Verify cross-platform equivalence via identical hash values. + expect( + await api.getAllNullableTypesHash(a), + await api.getAllNullableTypesHash(b), + ); + expect(await api.areAllNullableTypesEqual(a, b), isTrue); + }); + + testWidgets('Map equality with signed zero keys and values', ( + WidgetTester _, + ) async { + final api = HostIntegrationCoreApi(); + + final a = AllNullableTypes(map: {0.0: 'a', 'b': 0.0}); + final b = AllNullableTypes(map: {-0.0: 'a', 'b': -0.0}); + + expect(await api.areAllNullableTypesEqual(a, b), isTrue); + }); + + testWidgets('Map hashing with signed zero keys and values', ( + WidgetTester _, + ) async { + final api = HostIntegrationCoreApi(); + + final a = AllNullableTypes(map: {0.0: 'a', 'b': 0.0}); + final b = AllNullableTypes(map: {-0.0: 'a', 'b': -0.0}); + + expect( + await api.getAllNullableTypesHash(a), + await api.getAllNullableTypesHash(b), + ); + }); + + testWidgets('Map equality with null values and different keys', ( + WidgetTester _, + ) async { + final api = HostIntegrationCoreApi(); + + final a = AllNullableTypes(intMap: {1: null}); + final b = AllNullableTypes(intMap: {2: null}); + + expect(await api.areAllNullableTypesEqual(a, b), isFalse); + }); + + testWidgets('Deeply nested equality', (WidgetTester _) async { + final api = HostIntegrationCoreApi(); + + final a = AllNullableTypes( + allNullableTypes: AllNullableTypes(aNullableDouble: 0.0), + ); + final b = AllNullableTypes( + allNullableTypes: AllNullableTypes(aNullableDouble: -0.0), + ); + + expect(await api.areAllNullableTypesEqual(a, b), isTrue); + }); + + testWidgets('Hashing inequality across types with same values', ( + WidgetTester _, + ) async { + final api = HostIntegrationCoreApi(); + final a = AllNullableTypes(aNullableInt: 42); + final b = AllNullableTypesWithoutRecursion(aNullableInt: 42); + + expect(a.hashCode, isNot(b.hashCode)); + + expect( + await api.getAllNullableTypesHash(a), + isNot(await api.getAllNullableTypesWithoutRecursionHash(b)), + ); + }); }); group('Host async API tests', () { diff --git a/packages/pigeon/platform_tests/shared_test_plugin_code/lib/src/generated/core_tests.gen.dart b/packages/pigeon/platform_tests/shared_test_plugin_code/lib/src/generated/core_tests.gen.dart index 645223f45b40..c3e553e368c6 100644 --- a/packages/pigeon/platform_tests/shared_test_plugin_code/lib/src/generated/core_tests.gen.dart +++ b/packages/pigeon/platform_tests/shared_test_plugin_code/lib/src/generated/core_tests.gen.dart @@ -53,6 +53,15 @@ List wrapResponse({ } bool _deepEquals(Object? a, Object? b) { + if (identical(a, b)) { + return true; + } + if (a is double && b is double) { + if (a.isNaN && b.isNaN) { + return true; + } + return a == b; + } if (a is List && b is List) { return a.length == b.length && a.indexed.every( @@ -60,16 +69,52 @@ bool _deepEquals(Object? a, Object? b) { ); } if (a is Map && b is Map) { - return a.length == b.length && - a.entries.every( - (MapEntry entry) => - (b as Map).containsKey(entry.key) && - _deepEquals(entry.value, b[entry.key]), - ); + if (a.length != b.length) { + return false; + } + for (final MapEntry entryA in a.entries) { + bool found = false; + for (final MapEntry entryB in b.entries) { + if (_deepEquals(entryA.key, entryB.key)) { + if (_deepEquals(entryA.value, entryB.value)) { + found = true; + break; + } else { + return false; + } + } + } + if (!found) { + return false; + } + } + return true; } return a == b; } +int _deepHash(Object? value) { + if (value is List) { + return Object.hashAll(value.map(_deepHash)); + } + if (value is Map) { + int result = 0; + for (final MapEntry entry in value.entries) { + result += (_deepHash(entry.key) * 31) ^ _deepHash(entry.value); + } + return result; + } + if (value is double && value.isNaN) { + // Normalize NaN to a consistent hash. + return 0x7FF8000000000000.hashCode; + } + if (value is double && value == 0.0) { + // Normalize -0.0 to 0.0 so they have the same hash code. + return 0.0.hashCode; + } + return value.hashCode; +} + enum AnEnum { one, two, three, fortyTwo, fourHundredTwentyTwo } enum AnotherEnum { justInCase } @@ -101,12 +146,12 @@ class UnusedClass { if (identical(this, other)) { return true; } - return _deepEquals(encode(), other.encode()); + return _deepEquals(aField, other.aField); } @override // ignore: avoid_equals_and_hash_code_on_mutable_classes - int get hashCode => Object.hashAll(_toList()); + int get hashCode => _deepHash([runtimeType, ..._toList()]); } /// A class containing all supported types. @@ -280,12 +325,39 @@ class AllTypes { if (identical(this, other)) { return true; } - return _deepEquals(encode(), other.encode()); + return _deepEquals(aBool, other.aBool) && + _deepEquals(anInt, other.anInt) && + _deepEquals(anInt64, other.anInt64) && + _deepEquals(aDouble, other.aDouble) && + _deepEquals(aByteArray, other.aByteArray) && + _deepEquals(a4ByteArray, other.a4ByteArray) && + _deepEquals(a8ByteArray, other.a8ByteArray) && + _deepEquals(aFloatArray, other.aFloatArray) && + _deepEquals(anEnum, other.anEnum) && + _deepEquals(anotherEnum, other.anotherEnum) && + _deepEquals(aString, other.aString) && + _deepEquals(anObject, other.anObject) && + _deepEquals(list, other.list) && + _deepEquals(stringList, other.stringList) && + _deepEquals(intList, other.intList) && + _deepEquals(doubleList, other.doubleList) && + _deepEquals(boolList, other.boolList) && + _deepEquals(enumList, other.enumList) && + _deepEquals(objectList, other.objectList) && + _deepEquals(listList, other.listList) && + _deepEquals(mapList, other.mapList) && + _deepEquals(map, other.map) && + _deepEquals(stringMap, other.stringMap) && + _deepEquals(intMap, other.intMap) && + _deepEquals(enumMap, other.enumMap) && + _deepEquals(objectMap, other.objectMap) && + _deepEquals(listMap, other.listMap) && + _deepEquals(mapMap, other.mapMap); } @override // ignore: avoid_equals_and_hash_code_on_mutable_classes - int get hashCode => Object.hashAll(_toList()); + int get hashCode => _deepHash([runtimeType, ..._toList()]); } /// A class containing all supported nullable types. @@ -477,12 +549,42 @@ class AllNullableTypes { if (identical(this, other)) { return true; } - return _deepEquals(encode(), other.encode()); + return _deepEquals(aNullableBool, other.aNullableBool) && + _deepEquals(aNullableInt, other.aNullableInt) && + _deepEquals(aNullableInt64, other.aNullableInt64) && + _deepEquals(aNullableDouble, other.aNullableDouble) && + _deepEquals(aNullableByteArray, other.aNullableByteArray) && + _deepEquals(aNullable4ByteArray, other.aNullable4ByteArray) && + _deepEquals(aNullable8ByteArray, other.aNullable8ByteArray) && + _deepEquals(aNullableFloatArray, other.aNullableFloatArray) && + _deepEquals(aNullableEnum, other.aNullableEnum) && + _deepEquals(anotherNullableEnum, other.anotherNullableEnum) && + _deepEquals(aNullableString, other.aNullableString) && + _deepEquals(aNullableObject, other.aNullableObject) && + _deepEquals(allNullableTypes, other.allNullableTypes) && + _deepEquals(list, other.list) && + _deepEquals(stringList, other.stringList) && + _deepEquals(intList, other.intList) && + _deepEquals(doubleList, other.doubleList) && + _deepEquals(boolList, other.boolList) && + _deepEquals(enumList, other.enumList) && + _deepEquals(objectList, other.objectList) && + _deepEquals(listList, other.listList) && + _deepEquals(mapList, other.mapList) && + _deepEquals(recursiveClassList, other.recursiveClassList) && + _deepEquals(map, other.map) && + _deepEquals(stringMap, other.stringMap) && + _deepEquals(intMap, other.intMap) && + _deepEquals(enumMap, other.enumMap) && + _deepEquals(objectMap, other.objectMap) && + _deepEquals(listMap, other.listMap) && + _deepEquals(mapMap, other.mapMap) && + _deepEquals(recursiveClassMap, other.recursiveClassMap); } @override // ignore: avoid_equals_and_hash_code_on_mutable_classes - int get hashCode => Object.hashAll(_toList()); + int get hashCode => _deepHash([runtimeType, ..._toList()]); } /// The primary purpose for this class is to ensure coverage of Swift structs @@ -660,12 +762,39 @@ class AllNullableTypesWithoutRecursion { if (identical(this, other)) { return true; } - return _deepEquals(encode(), other.encode()); + return _deepEquals(aNullableBool, other.aNullableBool) && + _deepEquals(aNullableInt, other.aNullableInt) && + _deepEquals(aNullableInt64, other.aNullableInt64) && + _deepEquals(aNullableDouble, other.aNullableDouble) && + _deepEquals(aNullableByteArray, other.aNullableByteArray) && + _deepEquals(aNullable4ByteArray, other.aNullable4ByteArray) && + _deepEquals(aNullable8ByteArray, other.aNullable8ByteArray) && + _deepEquals(aNullableFloatArray, other.aNullableFloatArray) && + _deepEquals(aNullableEnum, other.aNullableEnum) && + _deepEquals(anotherNullableEnum, other.anotherNullableEnum) && + _deepEquals(aNullableString, other.aNullableString) && + _deepEquals(aNullableObject, other.aNullableObject) && + _deepEquals(list, other.list) && + _deepEquals(stringList, other.stringList) && + _deepEquals(intList, other.intList) && + _deepEquals(doubleList, other.doubleList) && + _deepEquals(boolList, other.boolList) && + _deepEquals(enumList, other.enumList) && + _deepEquals(objectList, other.objectList) && + _deepEquals(listList, other.listList) && + _deepEquals(mapList, other.mapList) && + _deepEquals(map, other.map) && + _deepEquals(stringMap, other.stringMap) && + _deepEquals(intMap, other.intMap) && + _deepEquals(enumMap, other.enumMap) && + _deepEquals(objectMap, other.objectMap) && + _deepEquals(listMap, other.listMap) && + _deepEquals(mapMap, other.mapMap); } @override // ignore: avoid_equals_and_hash_code_on_mutable_classes - int get hashCode => Object.hashAll(_toList()); + int get hashCode => _deepHash([runtimeType, ..._toList()]); } /// A class for testing nested class handling. @@ -739,12 +868,21 @@ class AllClassesWrapper { if (identical(this, other)) { return true; } - return _deepEquals(encode(), other.encode()); + return _deepEquals(allNullableTypes, other.allNullableTypes) && + _deepEquals( + allNullableTypesWithoutRecursion, + other.allNullableTypesWithoutRecursion, + ) && + _deepEquals(allTypes, other.allTypes) && + _deepEquals(classList, other.classList) && + _deepEquals(nullableClassList, other.nullableClassList) && + _deepEquals(classMap, other.classMap) && + _deepEquals(nullableClassMap, other.nullableClassMap); } @override // ignore: avoid_equals_and_hash_code_on_mutable_classes - int get hashCode => Object.hashAll(_toList()); + int get hashCode => _deepHash([runtimeType, ..._toList()]); } /// A data class containing a List, used in unit tests. @@ -775,12 +913,12 @@ class TestMessage { if (identical(this, other)) { return true; } - return _deepEquals(encode(), other.encode()); + return _deepEquals(testList, other.testList); } @override // ignore: avoid_equals_and_hash_code_on_mutable_classes - int get hashCode => Object.hashAll(_toList()); + int get hashCode => _deepHash([runtimeType, ..._toList()]); } class _PigeonCodec extends StandardMessageCodec { @@ -1560,6 +1698,77 @@ class HostIntegrationCoreApi { return pigeonVar_replyValue! as int; } + /// Returns the result of platform-side equality check. + Future areAllNullableTypesEqual( + AllNullableTypes a, + AllNullableTypes b, + ) async { + final pigeonVar_channelName = + 'dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi.areAllNullableTypesEqual$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send( + [a, b], + ); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + + final Object? pigeonVar_replyValue = _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: false, + ); + return pigeonVar_replyValue! as bool; + } + + /// Returns the platform-side hash code for the given object. + Future getAllNullableTypesHash(AllNullableTypes value) async { + final pigeonVar_channelName = + 'dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi.getAllNullableTypesHash$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send( + [value], + ); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + + final Object? pigeonVar_replyValue = _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: false, + ); + return pigeonVar_replyValue! as int; + } + + /// Returns the platform-side hash code for the given object. + Future getAllNullableTypesWithoutRecursionHash( + AllNullableTypesWithoutRecursion value, + ) async { + final pigeonVar_channelName = + 'dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi.getAllNullableTypesWithoutRecursionHash$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send( + [value], + ); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + + final Object? pigeonVar_replyValue = _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: false, + ); + return pigeonVar_replyValue! as int; + } + /// Returns the passed object, to test serialization and deserialization. Future echoAllNullableTypes( AllNullableTypes? everything, diff --git a/packages/pigeon/platform_tests/shared_test_plugin_code/lib/src/generated/enum.gen.dart b/packages/pigeon/platform_tests/shared_test_plugin_code/lib/src/generated/enum.gen.dart index ddd875d00933..06185b61738e 100644 --- a/packages/pigeon/platform_tests/shared_test_plugin_code/lib/src/generated/enum.gen.dart +++ b/packages/pigeon/platform_tests/shared_test_plugin_code/lib/src/generated/enum.gen.dart @@ -53,6 +53,15 @@ List wrapResponse({ } bool _deepEquals(Object? a, Object? b) { + if (identical(a, b)) { + return true; + } + if (a is double && b is double) { + if (a.isNaN && b.isNaN) { + return true; + } + return a == b; + } if (a is List && b is List) { return a.length == b.length && a.indexed.every( @@ -60,16 +69,52 @@ bool _deepEquals(Object? a, Object? b) { ); } if (a is Map && b is Map) { - return a.length == b.length && - a.entries.every( - (MapEntry entry) => - (b as Map).containsKey(entry.key) && - _deepEquals(entry.value, b[entry.key]), - ); + if (a.length != b.length) { + return false; + } + for (final MapEntry entryA in a.entries) { + bool found = false; + for (final MapEntry entryB in b.entries) { + if (_deepEquals(entryA.key, entryB.key)) { + if (_deepEquals(entryA.value, entryB.value)) { + found = true; + break; + } else { + return false; + } + } + } + if (!found) { + return false; + } + } + return true; } return a == b; } +int _deepHash(Object? value) { + if (value is List) { + return Object.hashAll(value.map(_deepHash)); + } + if (value is Map) { + int result = 0; + for (final MapEntry entry in value.entries) { + result += (_deepHash(entry.key) * 31) ^ _deepHash(entry.value); + } + return result; + } + if (value is double && value.isNaN) { + // Normalize NaN to a consistent hash. + return 0x7FF8000000000000.hashCode; + } + if (value is double && value == 0.0) { + // Normalize -0.0 to 0.0 so they have the same hash code. + return 0.0.hashCode; + } + return value.hashCode; +} + /// This comment is to test enum documentation comments. enum EnumState { /// This comment is to test enum member (Pending) documentation comments. @@ -114,12 +159,12 @@ class DataWithEnum { if (identical(this, other)) { return true; } - return _deepEquals(encode(), other.encode()); + return _deepEquals(state, other.state); } @override // ignore: avoid_equals_and_hash_code_on_mutable_classes - int get hashCode => Object.hashAll(_toList()); + int get hashCode => _deepHash([runtimeType, ..._toList()]); } class _PigeonCodec extends StandardMessageCodec { diff --git a/packages/pigeon/platform_tests/shared_test_plugin_code/lib/src/generated/event_channel_tests.gen.dart b/packages/pigeon/platform_tests/shared_test_plugin_code/lib/src/generated/event_channel_tests.gen.dart index e4460bdcd662..814f9efc5f50 100644 --- a/packages/pigeon/platform_tests/shared_test_plugin_code/lib/src/generated/event_channel_tests.gen.dart +++ b/packages/pigeon/platform_tests/shared_test_plugin_code/lib/src/generated/event_channel_tests.gen.dart @@ -14,6 +14,15 @@ import 'package:flutter/services.dart'; import 'package:meta/meta.dart' show immutable, protected, visibleForTesting; bool _deepEquals(Object? a, Object? b) { + if (identical(a, b)) { + return true; + } + if (a is double && b is double) { + if (a.isNaN && b.isNaN) { + return true; + } + return a == b; + } if (a is List && b is List) { return a.length == b.length && a.indexed.every( @@ -21,16 +30,52 @@ bool _deepEquals(Object? a, Object? b) { ); } if (a is Map && b is Map) { - return a.length == b.length && - a.entries.every( - (MapEntry entry) => - (b as Map).containsKey(entry.key) && - _deepEquals(entry.value, b[entry.key]), - ); + if (a.length != b.length) { + return false; + } + for (final MapEntry entryA in a.entries) { + bool found = false; + for (final MapEntry entryB in b.entries) { + if (_deepEquals(entryA.key, entryB.key)) { + if (_deepEquals(entryA.value, entryB.value)) { + found = true; + break; + } else { + return false; + } + } + } + if (!found) { + return false; + } + } + return true; } return a == b; } +int _deepHash(Object? value) { + if (value is List) { + return Object.hashAll(value.map(_deepHash)); + } + if (value is Map) { + int result = 0; + for (final MapEntry entry in value.entries) { + result += (_deepHash(entry.key) * 31) ^ _deepHash(entry.value); + } + return result; + } + if (value is double && value.isNaN) { + // Normalize NaN to a consistent hash. + return 0x7FF8000000000000.hashCode; + } + if (value is double && value == 0.0) { + // Normalize -0.0 to 0.0 so they have the same hash code. + return 0.0.hashCode; + } + return value.hashCode; +} + enum EventEnum { one, two, three, fortyTwo, fourHundredTwentyTwo } enum AnotherEventEnum { justInCase } @@ -225,12 +270,42 @@ class EventAllNullableTypes { if (identical(this, other)) { return true; } - return _deepEquals(encode(), other.encode()); + return _deepEquals(aNullableBool, other.aNullableBool) && + _deepEquals(aNullableInt, other.aNullableInt) && + _deepEquals(aNullableInt64, other.aNullableInt64) && + _deepEquals(aNullableDouble, other.aNullableDouble) && + _deepEquals(aNullableByteArray, other.aNullableByteArray) && + _deepEquals(aNullable4ByteArray, other.aNullable4ByteArray) && + _deepEquals(aNullable8ByteArray, other.aNullable8ByteArray) && + _deepEquals(aNullableFloatArray, other.aNullableFloatArray) && + _deepEquals(aNullableEnum, other.aNullableEnum) && + _deepEquals(anotherNullableEnum, other.anotherNullableEnum) && + _deepEquals(aNullableString, other.aNullableString) && + _deepEquals(aNullableObject, other.aNullableObject) && + _deepEquals(allNullableTypes, other.allNullableTypes) && + _deepEquals(list, other.list) && + _deepEquals(stringList, other.stringList) && + _deepEquals(intList, other.intList) && + _deepEquals(doubleList, other.doubleList) && + _deepEquals(boolList, other.boolList) && + _deepEquals(enumList, other.enumList) && + _deepEquals(objectList, other.objectList) && + _deepEquals(listList, other.listList) && + _deepEquals(mapList, other.mapList) && + _deepEquals(recursiveClassList, other.recursiveClassList) && + _deepEquals(map, other.map) && + _deepEquals(stringMap, other.stringMap) && + _deepEquals(intMap, other.intMap) && + _deepEquals(enumMap, other.enumMap) && + _deepEquals(objectMap, other.objectMap) && + _deepEquals(listMap, other.listMap) && + _deepEquals(mapMap, other.mapMap) && + _deepEquals(recursiveClassMap, other.recursiveClassMap); } @override // ignore: avoid_equals_and_hash_code_on_mutable_classes - int get hashCode => Object.hashAll(_toList()); + int get hashCode => _deepHash([runtimeType, ..._toList()]); } sealed class PlatformEvent {} @@ -262,12 +337,12 @@ class IntEvent extends PlatformEvent { if (identical(this, other)) { return true; } - return _deepEquals(encode(), other.encode()); + return _deepEquals(value, other.value); } @override // ignore: avoid_equals_and_hash_code_on_mutable_classes - int get hashCode => Object.hashAll(_toList()); + int get hashCode => _deepHash([runtimeType, ..._toList()]); } class StringEvent extends PlatformEvent { @@ -297,12 +372,12 @@ class StringEvent extends PlatformEvent { if (identical(this, other)) { return true; } - return _deepEquals(encode(), other.encode()); + return _deepEquals(value, other.value); } @override // ignore: avoid_equals_and_hash_code_on_mutable_classes - int get hashCode => Object.hashAll(_toList()); + int get hashCode => _deepHash([runtimeType, ..._toList()]); } class BoolEvent extends PlatformEvent { @@ -332,12 +407,12 @@ class BoolEvent extends PlatformEvent { if (identical(this, other)) { return true; } - return _deepEquals(encode(), other.encode()); + return _deepEquals(value, other.value); } @override // ignore: avoid_equals_and_hash_code_on_mutable_classes - int get hashCode => Object.hashAll(_toList()); + int get hashCode => _deepHash([runtimeType, ..._toList()]); } class DoubleEvent extends PlatformEvent { @@ -367,12 +442,12 @@ class DoubleEvent extends PlatformEvent { if (identical(this, other)) { return true; } - return _deepEquals(encode(), other.encode()); + return _deepEquals(value, other.value); } @override // ignore: avoid_equals_and_hash_code_on_mutable_classes - int get hashCode => Object.hashAll(_toList()); + int get hashCode => _deepHash([runtimeType, ..._toList()]); } class ObjectsEvent extends PlatformEvent { @@ -402,12 +477,12 @@ class ObjectsEvent extends PlatformEvent { if (identical(this, other)) { return true; } - return _deepEquals(encode(), other.encode()); + return _deepEquals(value, other.value); } @override // ignore: avoid_equals_and_hash_code_on_mutable_classes - int get hashCode => Object.hashAll(_toList()); + int get hashCode => _deepHash([runtimeType, ..._toList()]); } class EnumEvent extends PlatformEvent { @@ -437,12 +512,12 @@ class EnumEvent extends PlatformEvent { if (identical(this, other)) { return true; } - return _deepEquals(encode(), other.encode()); + return _deepEquals(value, other.value); } @override // ignore: avoid_equals_and_hash_code_on_mutable_classes - int get hashCode => Object.hashAll(_toList()); + int get hashCode => _deepHash([runtimeType, ..._toList()]); } class ClassEvent extends PlatformEvent { @@ -472,12 +547,12 @@ class ClassEvent extends PlatformEvent { if (identical(this, other)) { return true; } - return _deepEquals(encode(), other.encode()); + return _deepEquals(value, other.value); } @override // ignore: avoid_equals_and_hash_code_on_mutable_classes - int get hashCode => Object.hashAll(_toList()); + int get hashCode => _deepHash([runtimeType, ..._toList()]); } class _PigeonCodec extends StandardMessageCodec { diff --git a/packages/pigeon/platform_tests/shared_test_plugin_code/lib/src/generated/flutter_unittests.gen.dart b/packages/pigeon/platform_tests/shared_test_plugin_code/lib/src/generated/flutter_unittests.gen.dart index 4c6f0399711b..f34e47cf80b1 100644 --- a/packages/pigeon/platform_tests/shared_test_plugin_code/lib/src/generated/flutter_unittests.gen.dart +++ b/packages/pigeon/platform_tests/shared_test_plugin_code/lib/src/generated/flutter_unittests.gen.dart @@ -39,6 +39,15 @@ Object? _extractReplyValueOrThrow( } bool _deepEquals(Object? a, Object? b) { + if (identical(a, b)) { + return true; + } + if (a is double && b is double) { + if (a.isNaN && b.isNaN) { + return true; + } + return a == b; + } if (a is List && b is List) { return a.length == b.length && a.indexed.every( @@ -46,16 +55,52 @@ bool _deepEquals(Object? a, Object? b) { ); } if (a is Map && b is Map) { - return a.length == b.length && - a.entries.every( - (MapEntry entry) => - (b as Map).containsKey(entry.key) && - _deepEquals(entry.value, b[entry.key]), - ); + if (a.length != b.length) { + return false; + } + for (final MapEntry entryA in a.entries) { + bool found = false; + for (final MapEntry entryB in b.entries) { + if (_deepEquals(entryA.key, entryB.key)) { + if (_deepEquals(entryA.value, entryB.value)) { + found = true; + break; + } else { + return false; + } + } + } + if (!found) { + return false; + } + } + return true; } return a == b; } +int _deepHash(Object? value) { + if (value is List) { + return Object.hashAll(value.map(_deepHash)); + } + if (value is Map) { + int result = 0; + for (final MapEntry entry in value.entries) { + result += (_deepHash(entry.key) * 31) ^ _deepHash(entry.value); + } + return result; + } + if (value is double && value.isNaN) { + // Normalize NaN to a consistent hash. + return 0x7FF8000000000000.hashCode; + } + if (value is double && value == 0.0) { + // Normalize -0.0 to 0.0 so they have the same hash code. + return 0.0.hashCode; + } + return value.hashCode; +} + class FlutterSearchRequest { FlutterSearchRequest({this.query}); @@ -83,12 +128,12 @@ class FlutterSearchRequest { if (identical(this, other)) { return true; } - return _deepEquals(encode(), other.encode()); + return _deepEquals(query, other.query); } @override // ignore: avoid_equals_and_hash_code_on_mutable_classes - int get hashCode => Object.hashAll(_toList()); + int get hashCode => _deepHash([runtimeType, ..._toList()]); } class FlutterSearchReply { @@ -123,12 +168,12 @@ class FlutterSearchReply { if (identical(this, other)) { return true; } - return _deepEquals(encode(), other.encode()); + return _deepEquals(result, other.result) && _deepEquals(error, other.error); } @override // ignore: avoid_equals_and_hash_code_on_mutable_classes - int get hashCode => Object.hashAll(_toList()); + int get hashCode => _deepHash([runtimeType, ..._toList()]); } class FlutterSearchRequests { @@ -158,12 +203,12 @@ class FlutterSearchRequests { if (identical(this, other)) { return true; } - return _deepEquals(encode(), other.encode()); + return _deepEquals(requests, other.requests); } @override // ignore: avoid_equals_and_hash_code_on_mutable_classes - int get hashCode => Object.hashAll(_toList()); + int get hashCode => _deepHash([runtimeType, ..._toList()]); } class FlutterSearchReplies { @@ -193,12 +238,12 @@ class FlutterSearchReplies { if (identical(this, other)) { return true; } - return _deepEquals(encode(), other.encode()); + return _deepEquals(replies, other.replies); } @override // ignore: avoid_equals_and_hash_code_on_mutable_classes - int get hashCode => Object.hashAll(_toList()); + int get hashCode => _deepHash([runtimeType, ..._toList()]); } class _PigeonCodec extends StandardMessageCodec { diff --git a/packages/pigeon/platform_tests/shared_test_plugin_code/lib/src/generated/message.gen.dart b/packages/pigeon/platform_tests/shared_test_plugin_code/lib/src/generated/message.gen.dart index ed24efecdffd..5bccedeb9f2f 100644 --- a/packages/pigeon/platform_tests/shared_test_plugin_code/lib/src/generated/message.gen.dart +++ b/packages/pigeon/platform_tests/shared_test_plugin_code/lib/src/generated/message.gen.dart @@ -53,6 +53,15 @@ List wrapResponse({ } bool _deepEquals(Object? a, Object? b) { + if (identical(a, b)) { + return true; + } + if (a is double && b is double) { + if (a.isNaN && b.isNaN) { + return true; + } + return a == b; + } if (a is List && b is List) { return a.length == b.length && a.indexed.every( @@ -60,16 +69,52 @@ bool _deepEquals(Object? a, Object? b) { ); } if (a is Map && b is Map) { - return a.length == b.length && - a.entries.every( - (MapEntry entry) => - (b as Map).containsKey(entry.key) && - _deepEquals(entry.value, b[entry.key]), - ); + if (a.length != b.length) { + return false; + } + for (final MapEntry entryA in a.entries) { + bool found = false; + for (final MapEntry entryB in b.entries) { + if (_deepEquals(entryA.key, entryB.key)) { + if (_deepEquals(entryA.value, entryB.value)) { + found = true; + break; + } else { + return false; + } + } + } + if (!found) { + return false; + } + } + return true; } return a == b; } +int _deepHash(Object? value) { + if (value is List) { + return Object.hashAll(value.map(_deepHash)); + } + if (value is Map) { + int result = 0; + for (final MapEntry entry in value.entries) { + result += (_deepHash(entry.key) * 31) ^ _deepHash(entry.value); + } + return result; + } + if (value is double && value.isNaN) { + // Normalize NaN to a consistent hash. + return 0x7FF8000000000000.hashCode; + } + if (value is double && value == 0.0) { + // Normalize -0.0 to 0.0 so they have the same hash code. + return 0.0.hashCode; + } + return value.hashCode; +} + /// This comment is to test enum documentation comments. /// /// This comment also tests multiple line comments. @@ -120,12 +165,14 @@ class MessageSearchRequest { if (identical(this, other)) { return true; } - return _deepEquals(encode(), other.encode()); + return _deepEquals(query, other.query) && + _deepEquals(anInt, other.anInt) && + _deepEquals(aBool, other.aBool); } @override // ignore: avoid_equals_and_hash_code_on_mutable_classes - int get hashCode => Object.hashAll(_toList()); + int get hashCode => _deepHash([runtimeType, ..._toList()]); } /// This comment is to test class documentation comments. @@ -169,12 +216,14 @@ class MessageSearchReply { if (identical(this, other)) { return true; } - return _deepEquals(encode(), other.encode()); + return _deepEquals(result, other.result) && + _deepEquals(error, other.error) && + _deepEquals(state, other.state); } @override // ignore: avoid_equals_and_hash_code_on_mutable_classes - int get hashCode => Object.hashAll(_toList()); + int get hashCode => _deepHash([runtimeType, ..._toList()]); } /// This comment is to test class documentation comments. @@ -206,12 +255,12 @@ class MessageNested { if (identical(this, other)) { return true; } - return _deepEquals(encode(), other.encode()); + return _deepEquals(request, other.request); } @override // ignore: avoid_equals_and_hash_code_on_mutable_classes - int get hashCode => Object.hashAll(_toList()); + int get hashCode => _deepHash([runtimeType, ..._toList()]); } class _PigeonCodec extends StandardMessageCodec { diff --git a/packages/pigeon/platform_tests/shared_test_plugin_code/lib/src/generated/non_null_fields.gen.dart b/packages/pigeon/platform_tests/shared_test_plugin_code/lib/src/generated/non_null_fields.gen.dart index 4b5e0bf68c9e..e551956e8091 100644 --- a/packages/pigeon/platform_tests/shared_test_plugin_code/lib/src/generated/non_null_fields.gen.dart +++ b/packages/pigeon/platform_tests/shared_test_plugin_code/lib/src/generated/non_null_fields.gen.dart @@ -53,6 +53,15 @@ List wrapResponse({ } bool _deepEquals(Object? a, Object? b) { + if (identical(a, b)) { + return true; + } + if (a is double && b is double) { + if (a.isNaN && b.isNaN) { + return true; + } + return a == b; + } if (a is List && b is List) { return a.length == b.length && a.indexed.every( @@ -60,16 +69,52 @@ bool _deepEquals(Object? a, Object? b) { ); } if (a is Map && b is Map) { - return a.length == b.length && - a.entries.every( - (MapEntry entry) => - (b as Map).containsKey(entry.key) && - _deepEquals(entry.value, b[entry.key]), - ); + if (a.length != b.length) { + return false; + } + for (final MapEntry entryA in a.entries) { + bool found = false; + for (final MapEntry entryB in b.entries) { + if (_deepEquals(entryA.key, entryB.key)) { + if (_deepEquals(entryA.value, entryB.value)) { + found = true; + break; + } else { + return false; + } + } + } + if (!found) { + return false; + } + } + return true; } return a == b; } +int _deepHash(Object? value) { + if (value is List) { + return Object.hashAll(value.map(_deepHash)); + } + if (value is Map) { + int result = 0; + for (final MapEntry entry in value.entries) { + result += (_deepHash(entry.key) * 31) ^ _deepHash(entry.value); + } + return result; + } + if (value is double && value.isNaN) { + // Normalize NaN to a consistent hash. + return 0x7FF8000000000000.hashCode; + } + if (value is double && value == 0.0) { + // Normalize -0.0 to 0.0 so they have the same hash code. + return 0.0.hashCode; + } + return value.hashCode; +} + enum ReplyType { success, error } class NonNullFieldSearchRequest { @@ -100,12 +145,12 @@ class NonNullFieldSearchRequest { if (identical(this, other)) { return true; } - return _deepEquals(encode(), other.encode()); + return _deepEquals(query, other.query); } @override // ignore: avoid_equals_and_hash_code_on_mutable_classes - int get hashCode => Object.hashAll(_toList()); + int get hashCode => _deepHash([runtimeType, ..._toList()]); } class ExtraData { @@ -140,12 +185,13 @@ class ExtraData { if (identical(this, other)) { return true; } - return _deepEquals(encode(), other.encode()); + return _deepEquals(detailA, other.detailA) && + _deepEquals(detailB, other.detailB); } @override // ignore: avoid_equals_and_hash_code_on_mutable_classes - int get hashCode => Object.hashAll(_toList()); + int get hashCode => _deepHash([runtimeType, ..._toList()]); } class NonNullFieldSearchReply { @@ -195,12 +241,16 @@ class NonNullFieldSearchReply { if (identical(this, other)) { return true; } - return _deepEquals(encode(), other.encode()); + return _deepEquals(result, other.result) && + _deepEquals(error, other.error) && + _deepEquals(indices, other.indices) && + _deepEquals(extraData, other.extraData) && + _deepEquals(type, other.type); } @override // ignore: avoid_equals_and_hash_code_on_mutable_classes - int get hashCode => Object.hashAll(_toList()); + int get hashCode => _deepHash([runtimeType, ..._toList()]); } class _PigeonCodec extends StandardMessageCodec { diff --git a/packages/pigeon/platform_tests/shared_test_plugin_code/lib/src/generated/null_fields.gen.dart b/packages/pigeon/platform_tests/shared_test_plugin_code/lib/src/generated/null_fields.gen.dart index b4868ffebbce..6dbbbad8c197 100644 --- a/packages/pigeon/platform_tests/shared_test_plugin_code/lib/src/generated/null_fields.gen.dart +++ b/packages/pigeon/platform_tests/shared_test_plugin_code/lib/src/generated/null_fields.gen.dart @@ -53,6 +53,15 @@ List wrapResponse({ } bool _deepEquals(Object? a, Object? b) { + if (identical(a, b)) { + return true; + } + if (a is double && b is double) { + if (a.isNaN && b.isNaN) { + return true; + } + return a == b; + } if (a is List && b is List) { return a.length == b.length && a.indexed.every( @@ -60,16 +69,52 @@ bool _deepEquals(Object? a, Object? b) { ); } if (a is Map && b is Map) { - return a.length == b.length && - a.entries.every( - (MapEntry entry) => - (b as Map).containsKey(entry.key) && - _deepEquals(entry.value, b[entry.key]), - ); + if (a.length != b.length) { + return false; + } + for (final MapEntry entryA in a.entries) { + bool found = false; + for (final MapEntry entryB in b.entries) { + if (_deepEquals(entryA.key, entryB.key)) { + if (_deepEquals(entryA.value, entryB.value)) { + found = true; + break; + } else { + return false; + } + } + } + if (!found) { + return false; + } + } + return true; } return a == b; } +int _deepHash(Object? value) { + if (value is List) { + return Object.hashAll(value.map(_deepHash)); + } + if (value is Map) { + int result = 0; + for (final MapEntry entry in value.entries) { + result += (_deepHash(entry.key) * 31) ^ _deepHash(entry.value); + } + return result; + } + if (value is double && value.isNaN) { + // Normalize NaN to a consistent hash. + return 0x7FF8000000000000.hashCode; + } + if (value is double && value == 0.0) { + // Normalize -0.0 to 0.0 so they have the same hash code. + return 0.0.hashCode; + } + return value.hashCode; +} + enum NullFieldsSearchReplyType { success, failure } class NullFieldsSearchRequest { @@ -104,12 +149,13 @@ class NullFieldsSearchRequest { if (identical(this, other)) { return true; } - return _deepEquals(encode(), other.encode()); + return _deepEquals(query, other.query) && + _deepEquals(identifier, other.identifier); } @override // ignore: avoid_equals_and_hash_code_on_mutable_classes - int get hashCode => Object.hashAll(_toList()); + int get hashCode => _deepHash([runtimeType, ..._toList()]); } class NullFieldsSearchReply { @@ -159,12 +205,16 @@ class NullFieldsSearchReply { if (identical(this, other)) { return true; } - return _deepEquals(encode(), other.encode()); + return _deepEquals(result, other.result) && + _deepEquals(error, other.error) && + _deepEquals(indices, other.indices) && + _deepEquals(request, other.request) && + _deepEquals(type, other.type); } @override // ignore: avoid_equals_and_hash_code_on_mutable_classes - int get hashCode => Object.hashAll(_toList()); + int get hashCode => _deepHash([runtimeType, ..._toList()]); } class _PigeonCodec extends StandardMessageCodec { diff --git a/packages/pigeon/platform_tests/shared_test_plugin_code/test/equality_test.dart b/packages/pigeon/platform_tests/shared_test_plugin_code/test/equality_test.dart new file mode 100644 index 000000000000..2fb8d597a3fa --- /dev/null +++ b/packages/pigeon/platform_tests/shared_test_plugin_code/test/equality_test.dart @@ -0,0 +1,240 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter_test/flutter_test.dart'; +import 'package:shared_test_plugin_code/src/generated/core_tests.gen.dart'; +import 'package:shared_test_plugin_code/src/generated/non_null_fields.gen.dart'; +import 'package:shared_test_plugin_code/test_types.dart'; + +void main() { + test('NaN equality', () { + final list = [double.nan]; + final map = {1: double.nan}; + final all1 = AllNullableTypes( + aNullableDouble: double.nan, + doubleList: list, + recursiveClassList: [ + AllNullableTypes(aNullableDouble: double.nan), + ], + map: map, + ); + final all2 = AllNullableTypes( + aNullableDouble: double.nan, + doubleList: list, + recursiveClassList: [ + AllNullableTypes(aNullableDouble: double.nan), + ], + map: map, + ); + + expect(all1, all2); + expect(all1.hashCode, all2.hashCode); + }); + + test('Nested collection equality', () { + final all1 = AllNullableTypes( + listList: >[ + [1, 2], + ], + mapMap: >{ + 1: {'a': 'b'}, + }, + ); + final all2 = AllNullableTypes( + listList: >[ + [1, 2], + ], + mapMap: >{ + 1: {'a': 'b'}, + }, + ); + + expect(all1, all2); + expect(all1.hashCode, all2.hashCode); + }); + + test('Cross-type equality returns false', () { + final a = AllNullableTypes(aNullableInt: 1); + final b = AllNullableTypesWithoutRecursion(aNullableInt: 1); + // ignore: unrelated_type_equality_checks + expect(a == b, isFalse); + // ignore: unrelated_type_equality_checks + expect(b == a, isFalse); + }); + + test('non-null fields equality', () { + final request1 = NonNullFieldSearchRequest(query: 'hello'); + final request2 = NonNullFieldSearchRequest(query: 'hello'); + final request3 = NonNullFieldSearchRequest(query: 'world'); + + expect(request1, request2); + expect(request1, isNot(request3)); + expect(request1.hashCode, request2.hashCode); + }); + + group('deep equality', () { + final correctList = ['a', 2, 'three']; + final List matchingList = correctList.toList(); + final differentList = ['a', 2, 'three', 4.0]; + final correctMap = {'a': 1, 'b': 2, 'c': 'three'}; + final matchingMap = {...correctMap}; + final differentKeyMap = {'a': 1, 'b': 2, 'd': 'three'}; + final differentValueMap = {'a': 1, 'b': 2, 'c': 'five'}; + final correctListInMap = { + 'a': 1, + 'b': 2, + 'c': correctList, + }; + final matchingListInMap = { + 'a': 1, + 'b': 2, + 'c': matchingList, + }; + final differentListInMap = { + 'a': 1, + 'b': 2, + 'c': differentList, + }; + final correctMapInList = ['a', 2, correctMap]; + final matchingMapInList = ['a', 2, matchingMap]; + final differentKeyMapInList = ['a', 2, differentKeyMap]; + final differentValueMapInList = ['a', 2, differentValueMap]; + + test('equality method correctly checks deep equality', () { + final AllNullableTypes generic = genericAllNullableTypes; + final AllNullableTypes identical = AllNullableTypes.decode( + generic.encode(), + ); + expect(identical, generic); + }); + + test('equality method correctly identifies non-matching classes', () { + final AllNullableTypes generic = genericAllNullableTypes; + final allNull = AllNullableTypes(); + expect(allNull == generic, false); + }); + + test( + 'equality method correctly identifies non-matching lists in classes', + () { + final withList = AllNullableTypes(list: correctList); + final withDifferentList = AllNullableTypes(list: differentList); + expect(withList == withDifferentList, false); + }, + ); + + test( + 'equality method correctly identifies matching -but unique- lists in classes', + () { + final withList = AllNullableTypes(list: correctList); + final withDifferentList = AllNullableTypes(list: matchingList); + expect(withList, withDifferentList); + }, + ); + + test( + 'equality method correctly identifies non-matching keys in maps in classes', + () { + final withMap = AllNullableTypes(map: correctMap); + final withDifferentMap = AllNullableTypes(map: differentKeyMap); + expect(withMap == withDifferentMap, false); + }, + ); + + test( + 'equality method correctly identifies non-matching values in maps in classes', + () { + final withMap = AllNullableTypes(map: correctMap); + final withDifferentMap = AllNullableTypes(map: differentValueMap); + expect(withMap == withDifferentMap, false); + }, + ); + + test( + 'equality method correctly identifies matching -but unique- maps in classes', + () { + final withMap = AllNullableTypes(map: correctMap); + final withDifferentMap = AllNullableTypes(map: matchingMap); + expect(withMap, withDifferentMap); + }, + ); + test('signed zero equality', () { + final v1 = AllNullableTypes(aNullableDouble: 0.0); + final v2 = AllNullableTypes(aNullableDouble: -0.0); + expect(v1, v2); + expect(v1.hashCode, v2.hashCode); + }); + test('signed zero map key equality', () { + final v1 = AllNullableTypes(map: {0.0: 'a'}); + final v2 = AllNullableTypes(map: {-0.0: 'a'}); + expect(v1, v2); + expect(v1.hashCode, v2.hashCode); + }); + test('signed zero map value equality', () { + final v1 = AllNullableTypes(map: {'a': 0.0}); + final v2 = AllNullableTypes(map: {'a': -0.0}); + expect(v1, v2); + expect(v1.hashCode, v2.hashCode); + }); + test('signed zero nested list equality', () { + final v1 = AllNullableTypes(doubleList: [0.0]); + final v2 = AllNullableTypes(doubleList: [-0.0]); + expect(v1, v2); + expect(v1.hashCode, v2.hashCode); + }); + + test( + 'equality method correctly identifies non-matching lists nested in maps in classes', + () { + final withListInMap = AllNullableTypes(map: correctListInMap); + final withDifferentListInMap = AllNullableTypes( + map: differentListInMap, + ); + expect(withListInMap == withDifferentListInMap, false); + }, + ); + + test( + 'equality method correctly identifies matching -but unique- lists nested in maps in classes', + () { + final withListInMap = AllNullableTypes(map: correctListInMap); + final withDifferentListInMap = AllNullableTypes(map: matchingListInMap); + expect(withListInMap, withDifferentListInMap); + }, + ); + + test( + 'equality method correctly identifies non-matching keys in maps nested in lists in classes', + () { + final withMapInList = AllNullableTypes(list: correctMapInList); + final withDifferentMapInList = AllNullableTypes( + list: differentKeyMapInList, + ); + expect(withMapInList == withDifferentMapInList, false); + }, + ); + + test( + 'equality method correctly identifies non-matching values in maps nested in lists in classes', + () { + final withMapInList = AllNullableTypes(list: correctMapInList); + final withDifferentMapInList = AllNullableTypes( + list: differentValueMapInList, + ); + expect(withMapInList == withDifferentMapInList, false); + }, + ); + + test( + 'equality method correctly identifies matching -but unique- maps nested in lists in classes', + () { + final withMapInList = AllNullableTypes(list: correctMapInList); + final withDifferentMapInList = AllNullableTypes( + list: matchingMapInList, + ); + expect(withMapInList, withDifferentMapInList); + }, + ); + }); +} diff --git a/packages/pigeon/platform_tests/shared_test_plugin_code/test/generated_dart_test_code_test.dart b/packages/pigeon/platform_tests/shared_test_plugin_code/test/generated_dart_test_code_test.dart index 2603e0e57f47..e8046afc4545 100644 --- a/packages/pigeon/platform_tests/shared_test_plugin_code/test/generated_dart_test_code_test.dart +++ b/packages/pigeon/platform_tests/shared_test_plugin_code/test/generated_dart_test_code_test.dart @@ -6,10 +6,7 @@ import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; -import 'package:shared_test_plugin_code/src/generated/core_tests.gen.dart' - show AllNullableTypes; import 'package:shared_test_plugin_code/src/generated/message.gen.dart'; -import 'package:shared_test_plugin_code/test_types.dart'; import 'test_message.gen.dart'; @@ -44,146 +41,6 @@ class MockNested implements TestNestedApi { void main() { TestWidgetsFlutterBinding.ensureInitialized(); - group('equality method', () { - final correctList = ['a', 2, 'three']; - final List matchingList = correctList.toList(); - final differentList = ['a', 2, 'three', 4.0]; - final correctMap = {'a': 1, 'b': 2, 'c': 'three'}; - final matchingMap = {...correctMap}; - final differentKeyMap = {'a': 1, 'b': 2, 'd': 'three'}; - final differentValueMap = {'a': 1, 'b': 2, 'c': 'five'}; - final correctListInMap = { - 'a': 1, - 'b': 2, - 'c': correctList, - }; - final matchingListInMap = { - 'a': 1, - 'b': 2, - 'c': matchingList, - }; - final differentListInMap = { - 'a': 1, - 'b': 2, - 'c': differentList, - }; - final correctMapInList = ['a', 2, correctMap]; - final matchingMapInList = ['a', 2, matchingMap]; - final differentKeyMapInList = ['a', 2, differentKeyMap]; - final differentValueMapInList = ['a', 2, differentValueMap]; - - test('equality method correctly checks deep equality', () { - final AllNullableTypes generic = genericAllNullableTypes; - final AllNullableTypes identical = AllNullableTypes.decode( - generic.encode(), - ); - expect(identical, generic); - }); - - test('equality method correctly identifies non-matching classes', () { - final AllNullableTypes generic = genericAllNullableTypes; - final allNull = AllNullableTypes(); - expect(allNull == generic, false); - }); - - test( - 'equality method correctly identifies non-matching lists in classes', - () { - final withList = AllNullableTypes(list: correctList); - final withDifferentList = AllNullableTypes(list: differentList); - expect(withList == withDifferentList, false); - }, - ); - - test( - 'equality method correctly identifies matching -but unique- lists in classes', - () { - final withList = AllNullableTypes(list: correctList); - final withDifferentList = AllNullableTypes(list: matchingList); - expect(withList, withDifferentList); - }, - ); - - test( - 'equality method correctly identifies non-matching keys in maps in classes', - () { - final withMap = AllNullableTypes(map: correctMap); - final withDifferentMap = AllNullableTypes(map: differentKeyMap); - expect(withMap == withDifferentMap, false); - }, - ); - - test( - 'equality method correctly identifies non-matching values in maps in classes', - () { - final withMap = AllNullableTypes(map: correctMap); - final withDifferentMap = AllNullableTypes(map: differentValueMap); - expect(withMap == withDifferentMap, false); - }, - ); - - test( - 'equality method correctly identifies matching -but unique- maps in classes', - () { - final withMap = AllNullableTypes(map: correctMap); - final withDifferentMap = AllNullableTypes(map: matchingMap); - expect(withMap, withDifferentMap); - }, - ); - - test( - 'equality method correctly identifies non-matching lists nested in maps in classes', - () { - final withListInMap = AllNullableTypes(map: correctListInMap); - final withDifferentListInMap = AllNullableTypes( - map: differentListInMap, - ); - expect(withListInMap == withDifferentListInMap, false); - }, - ); - - test( - 'equality method correctly identifies matching -but unique- lists nested in maps in classes', - () { - final withListInMap = AllNullableTypes(map: correctListInMap); - final withDifferentListInMap = AllNullableTypes(map: matchingListInMap); - expect(withListInMap, withDifferentListInMap); - }, - ); - - test( - 'equality method correctly identifies non-matching keys in maps nested in lists in classes', - () { - final withMapInList = AllNullableTypes(list: correctMapInList); - final withDifferentMapInList = AllNullableTypes( - list: differentKeyMapInList, - ); - expect(withMapInList == withDifferentMapInList, false); - }, - ); - - test( - 'equality method correctly identifies non-matching values in maps nested in lists in classes', - () { - final withMapInList = AllNullableTypes(list: correctMapInList); - final withDifferentMapInList = AllNullableTypes( - list: differentValueMapInList, - ); - expect(withMapInList == withDifferentMapInList, false); - }, - ); - - test( - 'equality method correctly identifies matching -but unique- maps nested in lists in classes', - () { - final withMapInList = AllNullableTypes(list: correctMapInList); - final withDifferentMapInList = AllNullableTypes( - list: matchingMapInList, - ); - expect(withMapInList, withDifferentMapInList); - }, - ); - }); test('simple', () async { final api = MessageNestedApi(); final mock = MockNested(); diff --git a/packages/pigeon/platform_tests/test_plugin/android/build.gradle b/packages/pigeon/platform_tests/test_plugin/android/build.gradle.kts similarity index 61% rename from packages/pigeon/platform_tests/test_plugin/android/build.gradle rename to packages/pigeon/platform_tests/test_plugin/android/build.gradle.kts index 03ccddb3a69c..284efe74ecb6 100644 --- a/packages/pigeon/platform_tests/test_plugin/android/build.gradle +++ b/packages/pigeon/platform_tests/test_plugin/android/build.gradle.kts @@ -1,8 +1,10 @@ +import org.jetbrains.kotlin.gradle.dsl.JvmTarget + group = "com.example.test_plugin" version = "1.0-SNAPSHOT" buildscript { - ext.kotlin_version = '2.3.0' + val kotlinVersion = "2.3.0" repositories { google() mavenCentral() @@ -10,7 +12,7 @@ buildscript { dependencies { classpath("com.android.tools.build:gradle:8.13.1") - classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version") + classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion") } } @@ -21,8 +23,17 @@ allprojects { } } -apply plugin: 'com.android.library' -apply plugin: 'kotlin-android' +plugins { + id("com.android.library") + id("kotlin-android") +} + +kotlin { + compilerOptions { + jvmTarget = JvmTarget.fromTarget(JavaVersion.VERSION_17.toString()) + allWarningsAsErrors = true + } +} android { namespace = "com.example.test_plugin" @@ -33,27 +44,20 @@ android { targetCompatibility = JavaVersion.VERSION_17 } - kotlinOptions { - jvmTarget = JavaVersion.VERSION_17.toString() - allWarningsAsErrors = true - } - - sourceSets { - main.java.srcDirs += 'src/main/kotlin' - } - defaultConfig { minSdk = 24 } testOptions { - unitTests.includeAndroidResources = true - unitTests.returnDefaultValues = true - unitTests.all { - testLogging { - events "passed", "skipped", "failed", "standardOut", "standardError" - outputs.upToDateWhen {false} - showStandardStreams = true + unitTests { + isIncludeAndroidResources = true + isReturnDefaultValues = true + all { + it.outputs.upToDateWhen { false } + it.testLogging { + events("passed", "skipped", "failed", "standardOut", "standardError") + showStandardStreams = true + } } } } @@ -61,12 +65,12 @@ android { lint { checkAllWarnings = true warningsAsErrors = true - disable 'AndroidGradlePluginVersion', 'InvalidPackage', 'GradleDependency', 'NewerVersionAvailable' + disable.addAll(setOf("AndroidGradlePluginVersion", "InvalidPackage", "GradleDependency", "NewerVersionAvailable")) baseline = file("lint-baseline.xml") } dependencies { - compileOnly 'javax.annotation:javax.annotation-api:1.3.2' + compileOnly("javax.annotation:javax.annotation-api:1.3.2") testImplementation("junit:junit:4.13.2") testImplementation("io.mockk:mockk:1.14.9") // org.jetbrains.kotlin:kotlin-bom artifact purpose is to align kotlin stdlib and related code versions. diff --git a/packages/pigeon/platform_tests/test_plugin/android/settings.gradle b/packages/pigeon/platform_tests/test_plugin/android/settings.gradle deleted file mode 100644 index e9328f28412e..000000000000 --- a/packages/pigeon/platform_tests/test_plugin/android/settings.gradle +++ /dev/null @@ -1 +0,0 @@ -rootProject.name = 'test_plugin' diff --git a/packages/pigeon/platform_tests/test_plugin/android/settings.gradle.kts b/packages/pigeon/platform_tests/test_plugin/android/settings.gradle.kts new file mode 100644 index 000000000000..2e32f8d43572 --- /dev/null +++ b/packages/pigeon/platform_tests/test_plugin/android/settings.gradle.kts @@ -0,0 +1 @@ +rootProject.name = "test_plugin" diff --git a/packages/pigeon/platform_tests/test_plugin/android/src/main/kotlin/com/example/test_plugin/CoreTests.gen.kt b/packages/pigeon/platform_tests/test_plugin/android/src/main/kotlin/com/example/test_plugin/CoreTests.gen.kt index fe73e18c0998..338a53b8e3b3 100644 --- a/packages/pigeon/platform_tests/test_plugin/android/src/main/kotlin/com/example/test_plugin/CoreTests.gen.kt +++ b/packages/pigeon/platform_tests/test_plugin/android/src/main/kotlin/com/example/test_plugin/CoreTests.gen.kt @@ -38,7 +38,36 @@ private object CoreTestsPigeonUtils { } } + fun doubleEquals(a: Double, b: Double): Boolean { + // Normalize -0.0 to 0.0 and handle NaN equality. + return (if (a == 0.0) 0.0 else a) == (if (b == 0.0) 0.0 else b) || (a.isNaN() && b.isNaN()) + } + + fun floatEquals(a: Float, b: Float): Boolean { + // Normalize -0.0 to 0.0 and handle NaN equality. + return (if (a == 0.0f) 0.0f else a) == (if (b == 0.0f) 0.0f else b) || (a.isNaN() && b.isNaN()) + } + + fun doubleHash(d: Double): Int { + // Normalize -0.0 to 0.0 and handle NaN to ensure consistent hash codes. + val normalized = if (d == 0.0) 0.0 else d + val bits = java.lang.Double.doubleToLongBits(normalized) + return (bits xor (bits ushr 32)).toInt() + } + + fun floatHash(f: Float): Int { + // Normalize -0.0 to 0.0 and handle NaN to ensure consistent hash codes. + val normalized = if (f == 0.0f) 0.0f else f + return java.lang.Float.floatToIntBits(normalized) + } + fun deepEquals(a: Any?, b: Any?): Boolean { + if (a === b) { + return true + } + if (a == null || b == null) { + return false + } if (a is ByteArray && b is ByteArray) { return a.contentEquals(b) } @@ -49,20 +78,109 @@ private object CoreTestsPigeonUtils { return a.contentEquals(b) } if (a is DoubleArray && b is DoubleArray) { - return a.contentEquals(b) + if (a.size != b.size) return false + for (i in a.indices) { + if (!doubleEquals(a[i], b[i])) return false + } + return true + } + if (a is FloatArray && b is FloatArray) { + if (a.size != b.size) return false + for (i in a.indices) { + if (!floatEquals(a[i], b[i])) return false + } + return true } if (a is Array<*> && b is Array<*>) { - return a.size == b.size && a.indices.all { deepEquals(a[it], b[it]) } + if (a.size != b.size) return false + for (i in a.indices) { + if (!deepEquals(a[i], b[i])) return false + } + return true } if (a is List<*> && b is List<*>) { - return a.size == b.size && a.indices.all { deepEquals(a[it], b[it]) } + if (a.size != b.size) return false + val iterA = a.iterator() + val iterB = b.iterator() + while (iterA.hasNext() && iterB.hasNext()) { + if (!deepEquals(iterA.next(), iterB.next())) return false + } + return true } if (a is Map<*, *> && b is Map<*, *>) { - return a.size == b.size && - a.all { (b as Map).contains(it.key) && deepEquals(it.value, b[it.key]) } + if (a.size != b.size) return false + for (entry in a) { + val key = entry.key + var found = false + for (bEntry in b) { + if (deepEquals(key, bEntry.key)) { + if (deepEquals(entry.value, bEntry.value)) { + found = true + break + } else { + return false + } + } + } + if (!found) return false + } + return true + } + if (a is Double && b is Double) { + return doubleEquals(a, b) + } + if (a is Float && b is Float) { + return floatEquals(a, b) } return a == b } + + fun deepHash(value: Any?): Int { + return when (value) { + null -> 0 + is ByteArray -> value.contentHashCode() + is IntArray -> value.contentHashCode() + is LongArray -> value.contentHashCode() + is DoubleArray -> { + var result = 1 + for (item in value) { + result = 31 * result + doubleHash(item) + } + result + } + is FloatArray -> { + var result = 1 + for (item in value) { + result = 31 * result + floatHash(item) + } + result + } + is Array<*> -> { + var result = 1 + for (item in value) { + result = 31 * result + deepHash(item) + } + result + } + is List<*> -> { + var result = 1 + for (item in value) { + result = 31 * result + deepHash(item) + } + result + } + is Map<*, *> -> { + var result = 0 + for (entry in value) { + result += ((deepHash(entry.key) * 31) xor deepHash(entry.value)) + } + result + } + is Double -> doubleHash(value) + is Float -> floatHash(value) + else -> value.hashCode() + } + } } /** @@ -118,16 +236,21 @@ data class UnusedClass(val aField: Any? = null) { } override fun equals(other: Any?): Boolean { - if (other !is UnusedClass) { + if (other == null || other.javaClass != javaClass) { return false } if (this === other) { return true } - return CoreTestsPigeonUtils.deepEquals(toList(), other.toList()) + val other = other as UnusedClass + return CoreTestsPigeonUtils.deepEquals(this.aField, other.aField) } - override fun hashCode(): Int = toList().hashCode() + override fun hashCode(): Int { + var result = javaClass.hashCode() + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.aField) + return result + } } /** @@ -261,16 +384,75 @@ data class AllTypes( } override fun equals(other: Any?): Boolean { - if (other !is AllTypes) { + if (other == null || other.javaClass != javaClass) { return false } if (this === other) { return true } - return CoreTestsPigeonUtils.deepEquals(toList(), other.toList()) + val other = other as AllTypes + return CoreTestsPigeonUtils.deepEquals(this.aBool, other.aBool) && + CoreTestsPigeonUtils.deepEquals(this.anInt, other.anInt) && + CoreTestsPigeonUtils.deepEquals(this.anInt64, other.anInt64) && + CoreTestsPigeonUtils.deepEquals(this.aDouble, other.aDouble) && + CoreTestsPigeonUtils.deepEquals(this.aByteArray, other.aByteArray) && + CoreTestsPigeonUtils.deepEquals(this.a4ByteArray, other.a4ByteArray) && + CoreTestsPigeonUtils.deepEquals(this.a8ByteArray, other.a8ByteArray) && + CoreTestsPigeonUtils.deepEquals(this.aFloatArray, other.aFloatArray) && + CoreTestsPigeonUtils.deepEquals(this.anEnum, other.anEnum) && + CoreTestsPigeonUtils.deepEquals(this.anotherEnum, other.anotherEnum) && + CoreTestsPigeonUtils.deepEquals(this.aString, other.aString) && + CoreTestsPigeonUtils.deepEquals(this.anObject, other.anObject) && + CoreTestsPigeonUtils.deepEquals(this.list, other.list) && + CoreTestsPigeonUtils.deepEquals(this.stringList, other.stringList) && + CoreTestsPigeonUtils.deepEquals(this.intList, other.intList) && + CoreTestsPigeonUtils.deepEquals(this.doubleList, other.doubleList) && + CoreTestsPigeonUtils.deepEquals(this.boolList, other.boolList) && + CoreTestsPigeonUtils.deepEquals(this.enumList, other.enumList) && + CoreTestsPigeonUtils.deepEquals(this.objectList, other.objectList) && + CoreTestsPigeonUtils.deepEquals(this.listList, other.listList) && + CoreTestsPigeonUtils.deepEquals(this.mapList, other.mapList) && + CoreTestsPigeonUtils.deepEquals(this.map, other.map) && + CoreTestsPigeonUtils.deepEquals(this.stringMap, other.stringMap) && + CoreTestsPigeonUtils.deepEquals(this.intMap, other.intMap) && + CoreTestsPigeonUtils.deepEquals(this.enumMap, other.enumMap) && + CoreTestsPigeonUtils.deepEquals(this.objectMap, other.objectMap) && + CoreTestsPigeonUtils.deepEquals(this.listMap, other.listMap) && + CoreTestsPigeonUtils.deepEquals(this.mapMap, other.mapMap) } - override fun hashCode(): Int = toList().hashCode() + override fun hashCode(): Int { + var result = javaClass.hashCode() + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.aBool) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.anInt) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.anInt64) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.aDouble) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.aByteArray) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.a4ByteArray) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.a8ByteArray) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.aFloatArray) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.anEnum) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.anotherEnum) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.aString) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.anObject) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.list) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.stringList) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.intList) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.doubleList) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.boolList) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.enumList) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.objectList) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.listList) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.mapList) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.map) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.stringMap) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.intMap) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.enumMap) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.objectMap) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.listMap) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.mapMap) + return result + } } /** @@ -416,16 +598,81 @@ data class AllNullableTypes( } override fun equals(other: Any?): Boolean { - if (other !is AllNullableTypes) { + if (other == null || other.javaClass != javaClass) { return false } if (this === other) { return true } - return CoreTestsPigeonUtils.deepEquals(toList(), other.toList()) + val other = other as AllNullableTypes + return CoreTestsPigeonUtils.deepEquals(this.aNullableBool, other.aNullableBool) && + CoreTestsPigeonUtils.deepEquals(this.aNullableInt, other.aNullableInt) && + CoreTestsPigeonUtils.deepEquals(this.aNullableInt64, other.aNullableInt64) && + CoreTestsPigeonUtils.deepEquals(this.aNullableDouble, other.aNullableDouble) && + CoreTestsPigeonUtils.deepEquals(this.aNullableByteArray, other.aNullableByteArray) && + CoreTestsPigeonUtils.deepEquals(this.aNullable4ByteArray, other.aNullable4ByteArray) && + CoreTestsPigeonUtils.deepEquals(this.aNullable8ByteArray, other.aNullable8ByteArray) && + CoreTestsPigeonUtils.deepEquals(this.aNullableFloatArray, other.aNullableFloatArray) && + CoreTestsPigeonUtils.deepEquals(this.aNullableEnum, other.aNullableEnum) && + CoreTestsPigeonUtils.deepEquals(this.anotherNullableEnum, other.anotherNullableEnum) && + CoreTestsPigeonUtils.deepEquals(this.aNullableString, other.aNullableString) && + CoreTestsPigeonUtils.deepEquals(this.aNullableObject, other.aNullableObject) && + CoreTestsPigeonUtils.deepEquals(this.allNullableTypes, other.allNullableTypes) && + CoreTestsPigeonUtils.deepEquals(this.list, other.list) && + CoreTestsPigeonUtils.deepEquals(this.stringList, other.stringList) && + CoreTestsPigeonUtils.deepEquals(this.intList, other.intList) && + CoreTestsPigeonUtils.deepEquals(this.doubleList, other.doubleList) && + CoreTestsPigeonUtils.deepEquals(this.boolList, other.boolList) && + CoreTestsPigeonUtils.deepEquals(this.enumList, other.enumList) && + CoreTestsPigeonUtils.deepEquals(this.objectList, other.objectList) && + CoreTestsPigeonUtils.deepEquals(this.listList, other.listList) && + CoreTestsPigeonUtils.deepEquals(this.mapList, other.mapList) && + CoreTestsPigeonUtils.deepEquals(this.recursiveClassList, other.recursiveClassList) && + CoreTestsPigeonUtils.deepEquals(this.map, other.map) && + CoreTestsPigeonUtils.deepEquals(this.stringMap, other.stringMap) && + CoreTestsPigeonUtils.deepEquals(this.intMap, other.intMap) && + CoreTestsPigeonUtils.deepEquals(this.enumMap, other.enumMap) && + CoreTestsPigeonUtils.deepEquals(this.objectMap, other.objectMap) && + CoreTestsPigeonUtils.deepEquals(this.listMap, other.listMap) && + CoreTestsPigeonUtils.deepEquals(this.mapMap, other.mapMap) && + CoreTestsPigeonUtils.deepEquals(this.recursiveClassMap, other.recursiveClassMap) } - override fun hashCode(): Int = toList().hashCode() + override fun hashCode(): Int { + var result = javaClass.hashCode() + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.aNullableBool) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.aNullableInt) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.aNullableInt64) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.aNullableDouble) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.aNullableByteArray) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.aNullable4ByteArray) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.aNullable8ByteArray) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.aNullableFloatArray) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.aNullableEnum) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.anotherNullableEnum) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.aNullableString) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.aNullableObject) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.allNullableTypes) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.list) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.stringList) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.intList) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.doubleList) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.boolList) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.enumList) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.objectList) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.listList) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.mapList) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.recursiveClassList) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.map) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.stringMap) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.intMap) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.enumMap) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.objectMap) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.listMap) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.mapMap) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.recursiveClassMap) + return result + } } /** @@ -560,16 +807,75 @@ data class AllNullableTypesWithoutRecursion( } override fun equals(other: Any?): Boolean { - if (other !is AllNullableTypesWithoutRecursion) { + if (other == null || other.javaClass != javaClass) { return false } if (this === other) { return true } - return CoreTestsPigeonUtils.deepEquals(toList(), other.toList()) + val other = other as AllNullableTypesWithoutRecursion + return CoreTestsPigeonUtils.deepEquals(this.aNullableBool, other.aNullableBool) && + CoreTestsPigeonUtils.deepEquals(this.aNullableInt, other.aNullableInt) && + CoreTestsPigeonUtils.deepEquals(this.aNullableInt64, other.aNullableInt64) && + CoreTestsPigeonUtils.deepEquals(this.aNullableDouble, other.aNullableDouble) && + CoreTestsPigeonUtils.deepEquals(this.aNullableByteArray, other.aNullableByteArray) && + CoreTestsPigeonUtils.deepEquals(this.aNullable4ByteArray, other.aNullable4ByteArray) && + CoreTestsPigeonUtils.deepEquals(this.aNullable8ByteArray, other.aNullable8ByteArray) && + CoreTestsPigeonUtils.deepEquals(this.aNullableFloatArray, other.aNullableFloatArray) && + CoreTestsPigeonUtils.deepEquals(this.aNullableEnum, other.aNullableEnum) && + CoreTestsPigeonUtils.deepEquals(this.anotherNullableEnum, other.anotherNullableEnum) && + CoreTestsPigeonUtils.deepEquals(this.aNullableString, other.aNullableString) && + CoreTestsPigeonUtils.deepEquals(this.aNullableObject, other.aNullableObject) && + CoreTestsPigeonUtils.deepEquals(this.list, other.list) && + CoreTestsPigeonUtils.deepEquals(this.stringList, other.stringList) && + CoreTestsPigeonUtils.deepEquals(this.intList, other.intList) && + CoreTestsPigeonUtils.deepEquals(this.doubleList, other.doubleList) && + CoreTestsPigeonUtils.deepEquals(this.boolList, other.boolList) && + CoreTestsPigeonUtils.deepEquals(this.enumList, other.enumList) && + CoreTestsPigeonUtils.deepEquals(this.objectList, other.objectList) && + CoreTestsPigeonUtils.deepEquals(this.listList, other.listList) && + CoreTestsPigeonUtils.deepEquals(this.mapList, other.mapList) && + CoreTestsPigeonUtils.deepEquals(this.map, other.map) && + CoreTestsPigeonUtils.deepEquals(this.stringMap, other.stringMap) && + CoreTestsPigeonUtils.deepEquals(this.intMap, other.intMap) && + CoreTestsPigeonUtils.deepEquals(this.enumMap, other.enumMap) && + CoreTestsPigeonUtils.deepEquals(this.objectMap, other.objectMap) && + CoreTestsPigeonUtils.deepEquals(this.listMap, other.listMap) && + CoreTestsPigeonUtils.deepEquals(this.mapMap, other.mapMap) } - override fun hashCode(): Int = toList().hashCode() + override fun hashCode(): Int { + var result = javaClass.hashCode() + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.aNullableBool) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.aNullableInt) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.aNullableInt64) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.aNullableDouble) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.aNullableByteArray) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.aNullable4ByteArray) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.aNullable8ByteArray) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.aNullableFloatArray) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.aNullableEnum) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.anotherNullableEnum) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.aNullableString) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.aNullableObject) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.list) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.stringList) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.intList) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.doubleList) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.boolList) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.enumList) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.objectList) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.listList) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.mapList) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.map) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.stringMap) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.intMap) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.enumMap) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.objectMap) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.listMap) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.mapMap) + return result + } } /** @@ -623,16 +929,34 @@ data class AllClassesWrapper( } override fun equals(other: Any?): Boolean { - if (other !is AllClassesWrapper) { + if (other == null || other.javaClass != javaClass) { return false } if (this === other) { return true } - return CoreTestsPigeonUtils.deepEquals(toList(), other.toList()) + val other = other as AllClassesWrapper + return CoreTestsPigeonUtils.deepEquals(this.allNullableTypes, other.allNullableTypes) && + CoreTestsPigeonUtils.deepEquals( + this.allNullableTypesWithoutRecursion, other.allNullableTypesWithoutRecursion) && + CoreTestsPigeonUtils.deepEquals(this.allTypes, other.allTypes) && + CoreTestsPigeonUtils.deepEquals(this.classList, other.classList) && + CoreTestsPigeonUtils.deepEquals(this.nullableClassList, other.nullableClassList) && + CoreTestsPigeonUtils.deepEquals(this.classMap, other.classMap) && + CoreTestsPigeonUtils.deepEquals(this.nullableClassMap, other.nullableClassMap) } - override fun hashCode(): Int = toList().hashCode() + override fun hashCode(): Int { + var result = javaClass.hashCode() + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.allNullableTypes) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.allNullableTypesWithoutRecursion) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.allTypes) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.classList) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.nullableClassList) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.classMap) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.nullableClassMap) + return result + } } /** @@ -655,16 +979,21 @@ data class TestMessage(val testList: List? = null) { } override fun equals(other: Any?): Boolean { - if (other !is TestMessage) { + if (other == null || other.javaClass != javaClass) { return false } if (this === other) { return true } - return CoreTestsPigeonUtils.deepEquals(toList(), other.toList()) + val other = other as TestMessage + return CoreTestsPigeonUtils.deepEquals(this.testList, other.testList) } - override fun hashCode(): Int = toList().hashCode() + override fun hashCode(): Int { + var result = javaClass.hashCode() + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.testList) + return result + } } private open class CoreTestsPigeonCodec : StandardMessageCodec() { @@ -808,6 +1137,12 @@ interface HostIntegrationCoreApi { fun echoOptionalDefaultDouble(aDouble: Double): Double /** Returns passed in int. */ fun echoRequiredInt(anInt: Long): Long + /** Returns the result of platform-side equality check. */ + fun areAllNullableTypesEqual(a: AllNullableTypes, b: AllNullableTypes): Boolean + /** Returns the platform-side hash code for the given object. */ + fun getAllNullableTypesHash(value: AllNullableTypes): Long + /** Returns the platform-side hash code for the given object. */ + fun getAllNullableTypesWithoutRecursionHash(value: AllNullableTypesWithoutRecursion): Long /** Returns the passed object, to test serialization and deserialization. */ fun echoAllNullableTypes(everything: AllNullableTypes?): AllNullableTypes? /** Returns the passed object, to test serialization and deserialization. */ @@ -1900,6 +2235,73 @@ interface HostIntegrationCoreApi { channel.setMessageHandler(null) } } + run { + val channel = + BasicMessageChannel( + binaryMessenger, + "dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi.areAllNullableTypesEqual$separatedMessageChannelSuffix", + codec) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val aArg = args[0] as AllNullableTypes + val bArg = args[1] as AllNullableTypes + val wrapped: List = + try { + listOf(api.areAllNullableTypesEqual(aArg, bArg)) + } catch (exception: Throwable) { + CoreTestsPigeonUtils.wrapError(exception) + } + reply.reply(wrapped) + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = + BasicMessageChannel( + binaryMessenger, + "dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi.getAllNullableTypesHash$separatedMessageChannelSuffix", + codec) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val valueArg = args[0] as AllNullableTypes + val wrapped: List = + try { + listOf(api.getAllNullableTypesHash(valueArg)) + } catch (exception: Throwable) { + CoreTestsPigeonUtils.wrapError(exception) + } + reply.reply(wrapped) + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = + BasicMessageChannel( + binaryMessenger, + "dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi.getAllNullableTypesWithoutRecursionHash$separatedMessageChannelSuffix", + codec) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val valueArg = args[0] as AllNullableTypesWithoutRecursion + val wrapped: List = + try { + listOf(api.getAllNullableTypesWithoutRecursionHash(valueArg)) + } catch (exception: Throwable) { + CoreTestsPigeonUtils.wrapError(exception) + } + reply.reply(wrapped) + } + } else { + channel.setMessageHandler(null) + } + } run { val channel = BasicMessageChannel( diff --git a/packages/pigeon/platform_tests/test_plugin/android/src/main/kotlin/com/example/test_plugin/EventChannelTests.gen.kt b/packages/pigeon/platform_tests/test_plugin/android/src/main/kotlin/com/example/test_plugin/EventChannelTests.gen.kt index a3f79976d792..b98e54fef79c 100644 --- a/packages/pigeon/platform_tests/test_plugin/android/src/main/kotlin/com/example/test_plugin/EventChannelTests.gen.kt +++ b/packages/pigeon/platform_tests/test_plugin/android/src/main/kotlin/com/example/test_plugin/EventChannelTests.gen.kt @@ -16,7 +16,36 @@ import java.io.ByteArrayOutputStream import java.nio.ByteBuffer private object EventChannelTestsPigeonUtils { + fun doubleEquals(a: Double, b: Double): Boolean { + // Normalize -0.0 to 0.0 and handle NaN equality. + return (if (a == 0.0) 0.0 else a) == (if (b == 0.0) 0.0 else b) || (a.isNaN() && b.isNaN()) + } + + fun floatEquals(a: Float, b: Float): Boolean { + // Normalize -0.0 to 0.0 and handle NaN equality. + return (if (a == 0.0f) 0.0f else a) == (if (b == 0.0f) 0.0f else b) || (a.isNaN() && b.isNaN()) + } + + fun doubleHash(d: Double): Int { + // Normalize -0.0 to 0.0 and handle NaN to ensure consistent hash codes. + val normalized = if (d == 0.0) 0.0 else d + val bits = java.lang.Double.doubleToLongBits(normalized) + return (bits xor (bits ushr 32)).toInt() + } + + fun floatHash(f: Float): Int { + // Normalize -0.0 to 0.0 and handle NaN to ensure consistent hash codes. + val normalized = if (f == 0.0f) 0.0f else f + return java.lang.Float.floatToIntBits(normalized) + } + fun deepEquals(a: Any?, b: Any?): Boolean { + if (a === b) { + return true + } + if (a == null || b == null) { + return false + } if (a is ByteArray && b is ByteArray) { return a.contentEquals(b) } @@ -27,20 +56,109 @@ private object EventChannelTestsPigeonUtils { return a.contentEquals(b) } if (a is DoubleArray && b is DoubleArray) { - return a.contentEquals(b) + if (a.size != b.size) return false + for (i in a.indices) { + if (!doubleEquals(a[i], b[i])) return false + } + return true + } + if (a is FloatArray && b is FloatArray) { + if (a.size != b.size) return false + for (i in a.indices) { + if (!floatEquals(a[i], b[i])) return false + } + return true } if (a is Array<*> && b is Array<*>) { - return a.size == b.size && a.indices.all { deepEquals(a[it], b[it]) } + if (a.size != b.size) return false + for (i in a.indices) { + if (!deepEquals(a[i], b[i])) return false + } + return true } if (a is List<*> && b is List<*>) { - return a.size == b.size && a.indices.all { deepEquals(a[it], b[it]) } + if (a.size != b.size) return false + val iterA = a.iterator() + val iterB = b.iterator() + while (iterA.hasNext() && iterB.hasNext()) { + if (!deepEquals(iterA.next(), iterB.next())) return false + } + return true } if (a is Map<*, *> && b is Map<*, *>) { - return a.size == b.size && - a.all { (b as Map).contains(it.key) && deepEquals(it.value, b[it.key]) } + if (a.size != b.size) return false + for (entry in a) { + val key = entry.key + var found = false + for (bEntry in b) { + if (deepEquals(key, bEntry.key)) { + if (deepEquals(entry.value, bEntry.value)) { + found = true + break + } else { + return false + } + } + } + if (!found) return false + } + return true + } + if (a is Double && b is Double) { + return doubleEquals(a, b) + } + if (a is Float && b is Float) { + return floatEquals(a, b) } return a == b } + + fun deepHash(value: Any?): Int { + return when (value) { + null -> 0 + is ByteArray -> value.contentHashCode() + is IntArray -> value.contentHashCode() + is LongArray -> value.contentHashCode() + is DoubleArray -> { + var result = 1 + for (item in value) { + result = 31 * result + doubleHash(item) + } + result + } + is FloatArray -> { + var result = 1 + for (item in value) { + result = 31 * result + floatHash(item) + } + result + } + is Array<*> -> { + var result = 1 + for (item in value) { + result = 31 * result + deepHash(item) + } + result + } + is List<*> -> { + var result = 1 + for (item in value) { + result = 31 * result + deepHash(item) + } + result + } + is Map<*, *> -> { + var result = 0 + for (entry in value) { + result += ((deepHash(entry.key) * 31) xor deepHash(entry.value)) + } + result + } + is Double -> doubleHash(value) + is Float -> floatHash(value) + else -> value.hashCode() + } + } } /** @@ -223,16 +341,87 @@ data class EventAllNullableTypes( } override fun equals(other: Any?): Boolean { - if (other !is EventAllNullableTypes) { + if (other == null || other.javaClass != javaClass) { return false } if (this === other) { return true } - return EventChannelTestsPigeonUtils.deepEquals(toList(), other.toList()) + val other = other as EventAllNullableTypes + return EventChannelTestsPigeonUtils.deepEquals(this.aNullableBool, other.aNullableBool) && + EventChannelTestsPigeonUtils.deepEquals(this.aNullableInt, other.aNullableInt) && + EventChannelTestsPigeonUtils.deepEquals(this.aNullableInt64, other.aNullableInt64) && + EventChannelTestsPigeonUtils.deepEquals(this.aNullableDouble, other.aNullableDouble) && + EventChannelTestsPigeonUtils.deepEquals( + this.aNullableByteArray, other.aNullableByteArray) && + EventChannelTestsPigeonUtils.deepEquals( + this.aNullable4ByteArray, other.aNullable4ByteArray) && + EventChannelTestsPigeonUtils.deepEquals( + this.aNullable8ByteArray, other.aNullable8ByteArray) && + EventChannelTestsPigeonUtils.deepEquals( + this.aNullableFloatArray, other.aNullableFloatArray) && + EventChannelTestsPigeonUtils.deepEquals(this.aNullableEnum, other.aNullableEnum) && + EventChannelTestsPigeonUtils.deepEquals( + this.anotherNullableEnum, other.anotherNullableEnum) && + EventChannelTestsPigeonUtils.deepEquals(this.aNullableString, other.aNullableString) && + EventChannelTestsPigeonUtils.deepEquals(this.aNullableObject, other.aNullableObject) && + EventChannelTestsPigeonUtils.deepEquals(this.allNullableTypes, other.allNullableTypes) && + EventChannelTestsPigeonUtils.deepEquals(this.list, other.list) && + EventChannelTestsPigeonUtils.deepEquals(this.stringList, other.stringList) && + EventChannelTestsPigeonUtils.deepEquals(this.intList, other.intList) && + EventChannelTestsPigeonUtils.deepEquals(this.doubleList, other.doubleList) && + EventChannelTestsPigeonUtils.deepEquals(this.boolList, other.boolList) && + EventChannelTestsPigeonUtils.deepEquals(this.enumList, other.enumList) && + EventChannelTestsPigeonUtils.deepEquals(this.objectList, other.objectList) && + EventChannelTestsPigeonUtils.deepEquals(this.listList, other.listList) && + EventChannelTestsPigeonUtils.deepEquals(this.mapList, other.mapList) && + EventChannelTestsPigeonUtils.deepEquals( + this.recursiveClassList, other.recursiveClassList) && + EventChannelTestsPigeonUtils.deepEquals(this.map, other.map) && + EventChannelTestsPigeonUtils.deepEquals(this.stringMap, other.stringMap) && + EventChannelTestsPigeonUtils.deepEquals(this.intMap, other.intMap) && + EventChannelTestsPigeonUtils.deepEquals(this.enumMap, other.enumMap) && + EventChannelTestsPigeonUtils.deepEquals(this.objectMap, other.objectMap) && + EventChannelTestsPigeonUtils.deepEquals(this.listMap, other.listMap) && + EventChannelTestsPigeonUtils.deepEquals(this.mapMap, other.mapMap) && + EventChannelTestsPigeonUtils.deepEquals(this.recursiveClassMap, other.recursiveClassMap) + } + + override fun hashCode(): Int { + var result = javaClass.hashCode() + result = 31 * result + EventChannelTestsPigeonUtils.deepHash(this.aNullableBool) + result = 31 * result + EventChannelTestsPigeonUtils.deepHash(this.aNullableInt) + result = 31 * result + EventChannelTestsPigeonUtils.deepHash(this.aNullableInt64) + result = 31 * result + EventChannelTestsPigeonUtils.deepHash(this.aNullableDouble) + result = 31 * result + EventChannelTestsPigeonUtils.deepHash(this.aNullableByteArray) + result = 31 * result + EventChannelTestsPigeonUtils.deepHash(this.aNullable4ByteArray) + result = 31 * result + EventChannelTestsPigeonUtils.deepHash(this.aNullable8ByteArray) + result = 31 * result + EventChannelTestsPigeonUtils.deepHash(this.aNullableFloatArray) + result = 31 * result + EventChannelTestsPigeonUtils.deepHash(this.aNullableEnum) + result = 31 * result + EventChannelTestsPigeonUtils.deepHash(this.anotherNullableEnum) + result = 31 * result + EventChannelTestsPigeonUtils.deepHash(this.aNullableString) + result = 31 * result + EventChannelTestsPigeonUtils.deepHash(this.aNullableObject) + result = 31 * result + EventChannelTestsPigeonUtils.deepHash(this.allNullableTypes) + result = 31 * result + EventChannelTestsPigeonUtils.deepHash(this.list) + result = 31 * result + EventChannelTestsPigeonUtils.deepHash(this.stringList) + result = 31 * result + EventChannelTestsPigeonUtils.deepHash(this.intList) + result = 31 * result + EventChannelTestsPigeonUtils.deepHash(this.doubleList) + result = 31 * result + EventChannelTestsPigeonUtils.deepHash(this.boolList) + result = 31 * result + EventChannelTestsPigeonUtils.deepHash(this.enumList) + result = 31 * result + EventChannelTestsPigeonUtils.deepHash(this.objectList) + result = 31 * result + EventChannelTestsPigeonUtils.deepHash(this.listList) + result = 31 * result + EventChannelTestsPigeonUtils.deepHash(this.mapList) + result = 31 * result + EventChannelTestsPigeonUtils.deepHash(this.recursiveClassList) + result = 31 * result + EventChannelTestsPigeonUtils.deepHash(this.map) + result = 31 * result + EventChannelTestsPigeonUtils.deepHash(this.stringMap) + result = 31 * result + EventChannelTestsPigeonUtils.deepHash(this.intMap) + result = 31 * result + EventChannelTestsPigeonUtils.deepHash(this.enumMap) + result = 31 * result + EventChannelTestsPigeonUtils.deepHash(this.objectMap) + result = 31 * result + EventChannelTestsPigeonUtils.deepHash(this.listMap) + result = 31 * result + EventChannelTestsPigeonUtils.deepHash(this.mapMap) + result = 31 * result + EventChannelTestsPigeonUtils.deepHash(this.recursiveClassMap) + return result } - - override fun hashCode(): Int = toList().hashCode() } /** @@ -256,16 +445,21 @@ data class IntEvent(val value: Long) : PlatformEvent() { } override fun equals(other: Any?): Boolean { - if (other !is IntEvent) { + if (other == null || other.javaClass != javaClass) { return false } if (this === other) { return true } - return EventChannelTestsPigeonUtils.deepEquals(toList(), other.toList()) + val other = other as IntEvent + return EventChannelTestsPigeonUtils.deepEquals(this.value, other.value) } - override fun hashCode(): Int = toList().hashCode() + override fun hashCode(): Int { + var result = javaClass.hashCode() + result = 31 * result + EventChannelTestsPigeonUtils.deepHash(this.value) + return result + } } /** Generated class from Pigeon that represents data sent in messages. */ @@ -284,16 +478,21 @@ data class StringEvent(val value: String) : PlatformEvent() { } override fun equals(other: Any?): Boolean { - if (other !is StringEvent) { + if (other == null || other.javaClass != javaClass) { return false } if (this === other) { return true } - return EventChannelTestsPigeonUtils.deepEquals(toList(), other.toList()) + val other = other as StringEvent + return EventChannelTestsPigeonUtils.deepEquals(this.value, other.value) } - override fun hashCode(): Int = toList().hashCode() + override fun hashCode(): Int { + var result = javaClass.hashCode() + result = 31 * result + EventChannelTestsPigeonUtils.deepHash(this.value) + return result + } } /** Generated class from Pigeon that represents data sent in messages. */ @@ -312,16 +511,21 @@ data class BoolEvent(val value: Boolean) : PlatformEvent() { } override fun equals(other: Any?): Boolean { - if (other !is BoolEvent) { + if (other == null || other.javaClass != javaClass) { return false } if (this === other) { return true } - return EventChannelTestsPigeonUtils.deepEquals(toList(), other.toList()) + val other = other as BoolEvent + return EventChannelTestsPigeonUtils.deepEquals(this.value, other.value) } - override fun hashCode(): Int = toList().hashCode() + override fun hashCode(): Int { + var result = javaClass.hashCode() + result = 31 * result + EventChannelTestsPigeonUtils.deepHash(this.value) + return result + } } /** Generated class from Pigeon that represents data sent in messages. */ @@ -340,16 +544,21 @@ data class DoubleEvent(val value: Double) : PlatformEvent() { } override fun equals(other: Any?): Boolean { - if (other !is DoubleEvent) { + if (other == null || other.javaClass != javaClass) { return false } if (this === other) { return true } - return EventChannelTestsPigeonUtils.deepEquals(toList(), other.toList()) + val other = other as DoubleEvent + return EventChannelTestsPigeonUtils.deepEquals(this.value, other.value) } - override fun hashCode(): Int = toList().hashCode() + override fun hashCode(): Int { + var result = javaClass.hashCode() + result = 31 * result + EventChannelTestsPigeonUtils.deepHash(this.value) + return result + } } /** Generated class from Pigeon that represents data sent in messages. */ @@ -368,16 +577,21 @@ data class ObjectsEvent(val value: Any) : PlatformEvent() { } override fun equals(other: Any?): Boolean { - if (other !is ObjectsEvent) { + if (other == null || other.javaClass != javaClass) { return false } if (this === other) { return true } - return EventChannelTestsPigeonUtils.deepEquals(toList(), other.toList()) + val other = other as ObjectsEvent + return EventChannelTestsPigeonUtils.deepEquals(this.value, other.value) } - override fun hashCode(): Int = toList().hashCode() + override fun hashCode(): Int { + var result = javaClass.hashCode() + result = 31 * result + EventChannelTestsPigeonUtils.deepHash(this.value) + return result + } } /** Generated class from Pigeon that represents data sent in messages. */ @@ -396,16 +610,21 @@ data class EnumEvent(val value: EventEnum) : PlatformEvent() { } override fun equals(other: Any?): Boolean { - if (other !is EnumEvent) { + if (other == null || other.javaClass != javaClass) { return false } if (this === other) { return true } - return EventChannelTestsPigeonUtils.deepEquals(toList(), other.toList()) + val other = other as EnumEvent + return EventChannelTestsPigeonUtils.deepEquals(this.value, other.value) } - override fun hashCode(): Int = toList().hashCode() + override fun hashCode(): Int { + var result = javaClass.hashCode() + result = 31 * result + EventChannelTestsPigeonUtils.deepHash(this.value) + return result + } } /** Generated class from Pigeon that represents data sent in messages. */ @@ -424,16 +643,21 @@ data class ClassEvent(val value: EventAllNullableTypes) : PlatformEvent() { } override fun equals(other: Any?): Boolean { - if (other !is ClassEvent) { + if (other == null || other.javaClass != javaClass) { return false } if (this === other) { return true } - return EventChannelTestsPigeonUtils.deepEquals(toList(), other.toList()) + val other = other as ClassEvent + return EventChannelTestsPigeonUtils.deepEquals(this.value, other.value) } - override fun hashCode(): Int = toList().hashCode() + override fun hashCode(): Int { + var result = javaClass.hashCode() + result = 31 * result + EventChannelTestsPigeonUtils.deepHash(this.value) + return result + } } private open class EventChannelTestsPigeonCodec : StandardMessageCodec() { diff --git a/packages/pigeon/platform_tests/test_plugin/android/src/main/kotlin/com/example/test_plugin/TestPlugin.kt b/packages/pigeon/platform_tests/test_plugin/android/src/main/kotlin/com/example/test_plugin/TestPlugin.kt index e032596170cc..ea402e91d7a4 100644 --- a/packages/pigeon/platform_tests/test_plugin/android/src/main/kotlin/com/example/test_plugin/TestPlugin.kt +++ b/packages/pigeon/platform_tests/test_plugin/android/src/main/kotlin/com/example/test_plugin/TestPlugin.kt @@ -53,6 +53,20 @@ class TestPlugin : FlutterPlugin, HostIntegrationCoreApi { return everything } + override fun areAllNullableTypesEqual(a: AllNullableTypes, b: AllNullableTypes): Boolean { + return a == b + } + + override fun getAllNullableTypesHash(value: AllNullableTypes): Long { + return value.hashCode().toLong() + } + + override fun getAllNullableTypesWithoutRecursionHash( + value: AllNullableTypesWithoutRecursion + ): Long { + return value.hashCode().toLong() + } + override fun echoAllNullableTypesWithoutRecursion( everything: AllNullableTypesWithoutRecursion? ): AllNullableTypesWithoutRecursion? { diff --git a/packages/pigeon/platform_tests/test_plugin/android/src/test/kotlin/com/example/test_plugin/AllDatatypesTest.kt b/packages/pigeon/platform_tests/test_plugin/android/src/test/kotlin/com/example/test_plugin/AllDatatypesTest.kt index e2f80062c6e2..28a27c985604 100644 --- a/packages/pigeon/platform_tests/test_plugin/android/src/test/kotlin/com/example/test_plugin/AllDatatypesTest.kt +++ b/packages/pigeon/platform_tests/test_plugin/android/src/test/kotlin/com/example/test_plugin/AllDatatypesTest.kt @@ -227,4 +227,69 @@ internal class AllDatatypesTest { val withDifferentMapInList = AllNullableTypes(list = matchingMapInList) assertEquals(withMapInList, withDifferentMapInList) } + + @Test + fun `equality method correctly identifies NaN matches`() { + val withNaN = AllNullableTypes(aNullableDouble = Double.NaN) + val withAnotherNaN = AllNullableTypes(aNullableDouble = Double.NaN) + assertEquals(withNaN, withAnotherNaN) + assertEquals(withNaN.hashCode(), withAnotherNaN.hashCode()) + } + + @Test + fun `cross-type equality returns false`() { + val a = AllNullableTypes(aNullableInt = 1) + val b = AllNullableTypesWithoutRecursion(aNullableInt = 1) + assertNotEquals(a, b) + assertNotEquals(b, a) + } + + @Test + fun `byteArray equality`() { + val a = AllNullableTypes(aNullableByteArray = byteArrayOf(1, 2, 3)) + val b = AllNullableTypes(aNullableByteArray = byteArrayOf(1, 2, 3)) + assertEquals(a, b) + assertEquals(a.hashCode(), b.hashCode()) + } + + @Test + fun `zero equality`() { + val a = AllNullableTypes(aNullableDouble = 0.0) + val b = AllNullableTypes(aNullableDouble = -0.0) + // In many platforms, 0.0 and -0.0 are treated as equal. + assertEquals(a, b) + assertEquals(a.hashCode(), b.hashCode()) + } + + @Test + fun `zero map key equality`() { + val a = AllNullableTypes(map = mapOf(0.0 to "a")) + val b = AllNullableTypes(map = mapOf(-0.0 to "a")) + assertEquals(a, b) + assertEquals(a.hashCode(), b.hashCode()) + } + + @Test + fun `nested NaN equality`() { + val a = AllNullableTypes(doubleList = listOf(Double.NaN)) + val b = AllNullableTypes(doubleList = listOf(Double.NaN)) + assertEquals(a, b) + assertEquals(a.hashCode(), b.hashCode()) + } + + @Test + fun `nested zero list equality`() { + val a = AllNullableTypes(doubleList = listOf(0.0)) + val b = AllNullableTypes(doubleList = listOf(-0.0)) + assertEquals(a, b) + assertEquals(a.hashCode(), b.hashCode()) + } + + @Test + fun `nested zero array equality`() { + val a = AllNullableTypes(aNullableFloatArray = doubleArrayOf(0.0)) + val b = AllNullableTypes(aNullableFloatArray = doubleArrayOf(-0.0)) + assertEquals(a, b) + assertEquals(a.hashCode(), b.hashCode()) + } } diff --git a/packages/pigeon/platform_tests/test_plugin/android/src/test/kotlin/com/example/test_plugin/NonNullFieldsTests.kt b/packages/pigeon/platform_tests/test_plugin/android/src/test/kotlin/com/example/test_plugin/NonNullFieldsTests.kt index e5e97394f18f..fad1532b0599 100644 --- a/packages/pigeon/platform_tests/test_plugin/android/src/test/kotlin/com/example/test_plugin/NonNullFieldsTests.kt +++ b/packages/pigeon/platform_tests/test_plugin/android/src/test/kotlin/com/example/test_plugin/NonNullFieldsTests.kt @@ -14,4 +14,15 @@ class NonNullFieldsTests { val request = NonNullFieldSearchRequest("hello") assertEquals("hello", request.query) } + + @Test + fun testEquality() { + val request1 = NonNullFieldSearchRequest("hello") + val request2 = NonNullFieldSearchRequest("hello") + val request3 = NonNullFieldSearchRequest("world") + + assertEquals(request1, request2) + assert(request1 != request3) + assertEquals(request1.hashCode(), request2.hashCode()) + } } diff --git a/packages/pigeon/platform_tests/test_plugin/darwin/test_plugin/Sources/test_plugin/CoreTests.gen.swift b/packages/pigeon/platform_tests/test_plugin/darwin/test_plugin/Sources/test_plugin/CoreTests.gen.swift index ddea768974b8..606d58783837 100644 --- a/packages/pigeon/platform_tests/test_plugin/darwin/test_plugin/Sources/test_plugin/CoreTests.gen.swift +++ b/packages/pigeon/platform_tests/test_plugin/darwin/test_plugin/Sources/test_plugin/CoreTests.gen.swift @@ -54,7 +54,7 @@ private func wrapError(_ error: Any) -> [Any?] { } return [ "\(error)", - "\(type(of: error))", + "\(Swift.type(of: error))", "Stacktrace: \(Thread.callStackSymbols)", ] } @@ -74,6 +74,19 @@ private func nilOrValue(_ value: Any?) -> T? { return value as! T? } +private func doubleEqualsCoreTests(_ lhs: Double, _ rhs: Double) -> Bool { + return (lhs.isNaN && rhs.isNaN) || lhs == rhs +} + +private func doubleHashCoreTests(_ value: Double, _ hasher: inout Hasher) { + if value.isNaN { + hasher.combine(0x7FF8_0000_0000_0000) + } else { + // Normalize -0.0 to 0.0 + hasher.combine(value == 0 ? 0 : value) + } +} + func deepEqualsCoreTests(_ lhs: Any?, _ rhs: Any?) -> Bool { let cleanLhs = nilOrValue(lhs) as Any? let cleanRhs = nilOrValue(rhs) as Any? @@ -84,56 +97,90 @@ func deepEqualsCoreTests(_ lhs: Any?, _ rhs: Any?) -> Bool { case (nil, _), (_, nil): return false - case is (Void, Void): + case (let lhs as AnyObject, let rhs as AnyObject) where lhs === rhs: return true - case let (cleanLhsHashable, cleanRhsHashable) as (AnyHashable, AnyHashable): - return cleanLhsHashable == cleanRhsHashable + case is (Void, Void): + return true - case let (cleanLhsArray, cleanRhsArray) as ([Any?], [Any?]): - guard cleanLhsArray.count == cleanRhsArray.count else { return false } - for (index, element) in cleanLhsArray.enumerated() { - if !deepEqualsCoreTests(element, cleanRhsArray[index]) { + case (let lhsArray, let rhsArray) as ([Any?], [Any?]): + guard lhsArray.count == rhsArray.count else { return false } + for (index, element) in lhsArray.enumerated() { + if !deepEqualsCoreTests(element, rhsArray[index]) { return false } } return true - case let (cleanLhsDictionary, cleanRhsDictionary) as ([AnyHashable: Any?], [AnyHashable: Any?]): - guard cleanLhsDictionary.count == cleanRhsDictionary.count else { return false } - for (key, cleanLhsValue) in cleanLhsDictionary { - guard cleanRhsDictionary.index(forKey: key) != nil else { return false } - if !deepEqualsCoreTests(cleanLhsValue, cleanRhsDictionary[key]!) { + case (let lhsArray, let rhsArray) as ([Double], [Double]): + guard lhsArray.count == rhsArray.count else { return false } + for (index, element) in lhsArray.enumerated() { + if !doubleEqualsCoreTests(element, rhsArray[index]) { return false } } return true + case (let lhsDictionary, let rhsDictionary) as ([AnyHashable: Any?], [AnyHashable: Any?]): + guard lhsDictionary.count == rhsDictionary.count else { return false } + for (lhsKey, lhsValue) in lhsDictionary { + var found = false + for (rhsKey, rhsValue) in rhsDictionary { + if deepEqualsCoreTests(lhsKey, rhsKey) { + if deepEqualsCoreTests(lhsValue, rhsValue) { + found = true + break + } else { + return false + } + } + } + if !found { return false } + } + return true + + case (let lhs as Double, let rhs as Double): + return doubleEqualsCoreTests(lhs, rhs) + + case (let lhsHashable, let rhsHashable) as (AnyHashable, AnyHashable): + return lhsHashable == rhsHashable + default: - // Any other type shouldn't be able to be used with pigeon. File an issue if you find this to be untrue. return false } } func deepHashCoreTests(value: Any?, hasher: inout Hasher) { - if let valueList = value as? [AnyHashable] { - for item in valueList { deepHashCoreTests(value: item, hasher: &hasher) } - return + let cleanValue = nilOrValue(value) as Any? + if let cleanValue = cleanValue { + if let doubleValue = cleanValue as? Double { + doubleHashCoreTests(doubleValue, &hasher) + } else if let valueList = cleanValue as? [Any?] { + for item in valueList { + deepHashCoreTests(value: item, hasher: &hasher) + } + } else if let valueList = cleanValue as? [Double] { + for item in valueList { + doubleHashCoreTests(item, &hasher) + } + } else if let valueDict = cleanValue as? [AnyHashable: Any?] { + var result = 0 + for (key, value) in valueDict { + var entryKeyHasher = Hasher() + deepHashCoreTests(value: key, hasher: &entryKeyHasher) + var entryValueHasher = Hasher() + deepHashCoreTests(value: value, hasher: &entryValueHasher) + result = result &+ ((entryKeyHasher.finalize() &* 31) ^ entryValueHasher.finalize()) + } + hasher.combine(result) + } else if let hashableValue = cleanValue as? AnyHashable { + hasher.combine(hashableValue) + } else { + hasher.combine(String(describing: cleanValue)) + } + } else { + hasher.combine(0) } - - if let valueDict = value as? [AnyHashable: AnyHashable] { - for key in valueDict.keys { - hasher.combine(key) - deepHashCoreTests(value: valueDict[key]!, hasher: &hasher) - } - return - } - - if let hashableValue = value as? AnyHashable { - hasher.combine(hashableValue.hashValue) - } - - return hasher.combine(String(describing: value)) } enum AnEnum: Int { @@ -166,10 +213,15 @@ struct UnusedClass: Hashable { ] } static func == (lhs: UnusedClass, rhs: UnusedClass) -> Bool { - return deepEqualsCoreTests(lhs.toList(), rhs.toList()) + if Swift.type(of: lhs) != Swift.type(of: rhs) { + return false + } + return deepEqualsCoreTests(lhs.aField, rhs.aField) } + func hash(into hasher: inout Hasher) { - deepHashCoreTests(value: toList(), hasher: &hasher) + hasher.combine("UnusedClass") + deepHashCoreTests(value: aField, hasher: &hasher) } } @@ -301,10 +353,66 @@ struct AllTypes: Hashable { ] } static func == (lhs: AllTypes, rhs: AllTypes) -> Bool { - return deepEqualsCoreTests(lhs.toList(), rhs.toList()) + if Swift.type(of: lhs) != Swift.type(of: rhs) { + return false + } + return deepEqualsCoreTests(lhs.aBool, rhs.aBool) && deepEqualsCoreTests(lhs.anInt, rhs.anInt) + && deepEqualsCoreTests(lhs.anInt64, rhs.anInt64) + && deepEqualsCoreTests(lhs.aDouble, rhs.aDouble) + && deepEqualsCoreTests(lhs.aByteArray, rhs.aByteArray) + && deepEqualsCoreTests(lhs.a4ByteArray, rhs.a4ByteArray) + && deepEqualsCoreTests(lhs.a8ByteArray, rhs.a8ByteArray) + && deepEqualsCoreTests(lhs.aFloatArray, rhs.aFloatArray) + && deepEqualsCoreTests(lhs.anEnum, rhs.anEnum) + && deepEqualsCoreTests(lhs.anotherEnum, rhs.anotherEnum) + && deepEqualsCoreTests(lhs.aString, rhs.aString) + && deepEqualsCoreTests(lhs.anObject, rhs.anObject) && deepEqualsCoreTests(lhs.list, rhs.list) + && deepEqualsCoreTests(lhs.stringList, rhs.stringList) + && deepEqualsCoreTests(lhs.intList, rhs.intList) + && deepEqualsCoreTests(lhs.doubleList, rhs.doubleList) + && deepEqualsCoreTests(lhs.boolList, rhs.boolList) + && deepEqualsCoreTests(lhs.enumList, rhs.enumList) + && deepEqualsCoreTests(lhs.objectList, rhs.objectList) + && deepEqualsCoreTests(lhs.listList, rhs.listList) + && deepEqualsCoreTests(lhs.mapList, rhs.mapList) && deepEqualsCoreTests(lhs.map, rhs.map) + && deepEqualsCoreTests(lhs.stringMap, rhs.stringMap) + && deepEqualsCoreTests(lhs.intMap, rhs.intMap) + && deepEqualsCoreTests(lhs.enumMap, rhs.enumMap) + && deepEqualsCoreTests(lhs.objectMap, rhs.objectMap) + && deepEqualsCoreTests(lhs.listMap, rhs.listMap) + && deepEqualsCoreTests(lhs.mapMap, rhs.mapMap) } + func hash(into hasher: inout Hasher) { - deepHashCoreTests(value: toList(), hasher: &hasher) + hasher.combine("AllTypes") + deepHashCoreTests(value: aBool, hasher: &hasher) + deepHashCoreTests(value: anInt, hasher: &hasher) + deepHashCoreTests(value: anInt64, hasher: &hasher) + deepHashCoreTests(value: aDouble, hasher: &hasher) + deepHashCoreTests(value: aByteArray, hasher: &hasher) + deepHashCoreTests(value: a4ByteArray, hasher: &hasher) + deepHashCoreTests(value: a8ByteArray, hasher: &hasher) + deepHashCoreTests(value: aFloatArray, hasher: &hasher) + deepHashCoreTests(value: anEnum, hasher: &hasher) + deepHashCoreTests(value: anotherEnum, hasher: &hasher) + deepHashCoreTests(value: aString, hasher: &hasher) + deepHashCoreTests(value: anObject, hasher: &hasher) + deepHashCoreTests(value: list, hasher: &hasher) + deepHashCoreTests(value: stringList, hasher: &hasher) + deepHashCoreTests(value: intList, hasher: &hasher) + deepHashCoreTests(value: doubleList, hasher: &hasher) + deepHashCoreTests(value: boolList, hasher: &hasher) + deepHashCoreTests(value: enumList, hasher: &hasher) + deepHashCoreTests(value: objectList, hasher: &hasher) + deepHashCoreTests(value: listList, hasher: &hasher) + deepHashCoreTests(value: mapList, hasher: &hasher) + deepHashCoreTests(value: map, hasher: &hasher) + deepHashCoreTests(value: stringMap, hasher: &hasher) + deepHashCoreTests(value: intMap, hasher: &hasher) + deepHashCoreTests(value: enumMap, hasher: &hasher) + deepHashCoreTests(value: objectMap, hasher: &hasher) + deepHashCoreTests(value: listMap, hasher: &hasher) + deepHashCoreTests(value: mapMap, hasher: &hasher) } } @@ -513,13 +621,77 @@ class AllNullableTypes: Hashable { ] } static func == (lhs: AllNullableTypes, rhs: AllNullableTypes) -> Bool { + if Swift.type(of: lhs) != Swift.type(of: rhs) { + return false + } if lhs === rhs { return true } - return deepEqualsCoreTests(lhs.toList(), rhs.toList()) + return deepEqualsCoreTests(lhs.aNullableBool, rhs.aNullableBool) + && deepEqualsCoreTests(lhs.aNullableInt, rhs.aNullableInt) + && deepEqualsCoreTests(lhs.aNullableInt64, rhs.aNullableInt64) + && deepEqualsCoreTests(lhs.aNullableDouble, rhs.aNullableDouble) + && deepEqualsCoreTests(lhs.aNullableByteArray, rhs.aNullableByteArray) + && deepEqualsCoreTests(lhs.aNullable4ByteArray, rhs.aNullable4ByteArray) + && deepEqualsCoreTests(lhs.aNullable8ByteArray, rhs.aNullable8ByteArray) + && deepEqualsCoreTests(lhs.aNullableFloatArray, rhs.aNullableFloatArray) + && deepEqualsCoreTests(lhs.aNullableEnum, rhs.aNullableEnum) + && deepEqualsCoreTests(lhs.anotherNullableEnum, rhs.anotherNullableEnum) + && deepEqualsCoreTests(lhs.aNullableString, rhs.aNullableString) + && deepEqualsCoreTests(lhs.aNullableObject, rhs.aNullableObject) + && deepEqualsCoreTests(lhs.allNullableTypes, rhs.allNullableTypes) + && deepEqualsCoreTests(lhs.list, rhs.list) + && deepEqualsCoreTests(lhs.stringList, rhs.stringList) + && deepEqualsCoreTests(lhs.intList, rhs.intList) + && deepEqualsCoreTests(lhs.doubleList, rhs.doubleList) + && deepEqualsCoreTests(lhs.boolList, rhs.boolList) + && deepEqualsCoreTests(lhs.enumList, rhs.enumList) + && deepEqualsCoreTests(lhs.objectList, rhs.objectList) + && deepEqualsCoreTests(lhs.listList, rhs.listList) + && deepEqualsCoreTests(lhs.mapList, rhs.mapList) + && deepEqualsCoreTests(lhs.recursiveClassList, rhs.recursiveClassList) + && deepEqualsCoreTests(lhs.map, rhs.map) && deepEqualsCoreTests(lhs.stringMap, rhs.stringMap) + && deepEqualsCoreTests(lhs.intMap, rhs.intMap) + && deepEqualsCoreTests(lhs.enumMap, rhs.enumMap) + && deepEqualsCoreTests(lhs.objectMap, rhs.objectMap) + && deepEqualsCoreTests(lhs.listMap, rhs.listMap) + && deepEqualsCoreTests(lhs.mapMap, rhs.mapMap) + && deepEqualsCoreTests(lhs.recursiveClassMap, rhs.recursiveClassMap) } + func hash(into hasher: inout Hasher) { - deepHashCoreTests(value: toList(), hasher: &hasher) + hasher.combine("AllNullableTypes") + deepHashCoreTests(value: aNullableBool, hasher: &hasher) + deepHashCoreTests(value: aNullableInt, hasher: &hasher) + deepHashCoreTests(value: aNullableInt64, hasher: &hasher) + deepHashCoreTests(value: aNullableDouble, hasher: &hasher) + deepHashCoreTests(value: aNullableByteArray, hasher: &hasher) + deepHashCoreTests(value: aNullable4ByteArray, hasher: &hasher) + deepHashCoreTests(value: aNullable8ByteArray, hasher: &hasher) + deepHashCoreTests(value: aNullableFloatArray, hasher: &hasher) + deepHashCoreTests(value: aNullableEnum, hasher: &hasher) + deepHashCoreTests(value: anotherNullableEnum, hasher: &hasher) + deepHashCoreTests(value: aNullableString, hasher: &hasher) + deepHashCoreTests(value: aNullableObject, hasher: &hasher) + deepHashCoreTests(value: allNullableTypes, hasher: &hasher) + deepHashCoreTests(value: list, hasher: &hasher) + deepHashCoreTests(value: stringList, hasher: &hasher) + deepHashCoreTests(value: intList, hasher: &hasher) + deepHashCoreTests(value: doubleList, hasher: &hasher) + deepHashCoreTests(value: boolList, hasher: &hasher) + deepHashCoreTests(value: enumList, hasher: &hasher) + deepHashCoreTests(value: objectList, hasher: &hasher) + deepHashCoreTests(value: listList, hasher: &hasher) + deepHashCoreTests(value: mapList, hasher: &hasher) + deepHashCoreTests(value: recursiveClassList, hasher: &hasher) + deepHashCoreTests(value: map, hasher: &hasher) + deepHashCoreTests(value: stringMap, hasher: &hasher) + deepHashCoreTests(value: intMap, hasher: &hasher) + deepHashCoreTests(value: enumMap, hasher: &hasher) + deepHashCoreTests(value: objectMap, hasher: &hasher) + deepHashCoreTests(value: listMap, hasher: &hasher) + deepHashCoreTests(value: mapMap, hasher: &hasher) + deepHashCoreTests(value: recursiveClassMap, hasher: &hasher) } } @@ -655,10 +827,68 @@ struct AllNullableTypesWithoutRecursion: Hashable { static func == (lhs: AllNullableTypesWithoutRecursion, rhs: AllNullableTypesWithoutRecursion) -> Bool { - return deepEqualsCoreTests(lhs.toList(), rhs.toList()) + if Swift.type(of: lhs) != Swift.type(of: rhs) { + return false + } + return deepEqualsCoreTests(lhs.aNullableBool, rhs.aNullableBool) + && deepEqualsCoreTests(lhs.aNullableInt, rhs.aNullableInt) + && deepEqualsCoreTests(lhs.aNullableInt64, rhs.aNullableInt64) + && deepEqualsCoreTests(lhs.aNullableDouble, rhs.aNullableDouble) + && deepEqualsCoreTests(lhs.aNullableByteArray, rhs.aNullableByteArray) + && deepEqualsCoreTests(lhs.aNullable4ByteArray, rhs.aNullable4ByteArray) + && deepEqualsCoreTests(lhs.aNullable8ByteArray, rhs.aNullable8ByteArray) + && deepEqualsCoreTests(lhs.aNullableFloatArray, rhs.aNullableFloatArray) + && deepEqualsCoreTests(lhs.aNullableEnum, rhs.aNullableEnum) + && deepEqualsCoreTests(lhs.anotherNullableEnum, rhs.anotherNullableEnum) + && deepEqualsCoreTests(lhs.aNullableString, rhs.aNullableString) + && deepEqualsCoreTests(lhs.aNullableObject, rhs.aNullableObject) + && deepEqualsCoreTests(lhs.list, rhs.list) + && deepEqualsCoreTests(lhs.stringList, rhs.stringList) + && deepEqualsCoreTests(lhs.intList, rhs.intList) + && deepEqualsCoreTests(lhs.doubleList, rhs.doubleList) + && deepEqualsCoreTests(lhs.boolList, rhs.boolList) + && deepEqualsCoreTests(lhs.enumList, rhs.enumList) + && deepEqualsCoreTests(lhs.objectList, rhs.objectList) + && deepEqualsCoreTests(lhs.listList, rhs.listList) + && deepEqualsCoreTests(lhs.mapList, rhs.mapList) && deepEqualsCoreTests(lhs.map, rhs.map) + && deepEqualsCoreTests(lhs.stringMap, rhs.stringMap) + && deepEqualsCoreTests(lhs.intMap, rhs.intMap) + && deepEqualsCoreTests(lhs.enumMap, rhs.enumMap) + && deepEqualsCoreTests(lhs.objectMap, rhs.objectMap) + && deepEqualsCoreTests(lhs.listMap, rhs.listMap) + && deepEqualsCoreTests(lhs.mapMap, rhs.mapMap) } + func hash(into hasher: inout Hasher) { - deepHashCoreTests(value: toList(), hasher: &hasher) + hasher.combine("AllNullableTypesWithoutRecursion") + deepHashCoreTests(value: aNullableBool, hasher: &hasher) + deepHashCoreTests(value: aNullableInt, hasher: &hasher) + deepHashCoreTests(value: aNullableInt64, hasher: &hasher) + deepHashCoreTests(value: aNullableDouble, hasher: &hasher) + deepHashCoreTests(value: aNullableByteArray, hasher: &hasher) + deepHashCoreTests(value: aNullable4ByteArray, hasher: &hasher) + deepHashCoreTests(value: aNullable8ByteArray, hasher: &hasher) + deepHashCoreTests(value: aNullableFloatArray, hasher: &hasher) + deepHashCoreTests(value: aNullableEnum, hasher: &hasher) + deepHashCoreTests(value: anotherNullableEnum, hasher: &hasher) + deepHashCoreTests(value: aNullableString, hasher: &hasher) + deepHashCoreTests(value: aNullableObject, hasher: &hasher) + deepHashCoreTests(value: list, hasher: &hasher) + deepHashCoreTests(value: stringList, hasher: &hasher) + deepHashCoreTests(value: intList, hasher: &hasher) + deepHashCoreTests(value: doubleList, hasher: &hasher) + deepHashCoreTests(value: boolList, hasher: &hasher) + deepHashCoreTests(value: enumList, hasher: &hasher) + deepHashCoreTests(value: objectList, hasher: &hasher) + deepHashCoreTests(value: listList, hasher: &hasher) + deepHashCoreTests(value: mapList, hasher: &hasher) + deepHashCoreTests(value: map, hasher: &hasher) + deepHashCoreTests(value: stringMap, hasher: &hasher) + deepHashCoreTests(value: intMap, hasher: &hasher) + deepHashCoreTests(value: enumMap, hasher: &hasher) + deepHashCoreTests(value: objectMap, hasher: &hasher) + deepHashCoreTests(value: listMap, hasher: &hasher) + deepHashCoreTests(value: mapMap, hasher: &hasher) } } @@ -712,10 +942,28 @@ struct AllClassesWrapper: Hashable { ] } static func == (lhs: AllClassesWrapper, rhs: AllClassesWrapper) -> Bool { - return deepEqualsCoreTests(lhs.toList(), rhs.toList()) + if Swift.type(of: lhs) != Swift.type(of: rhs) { + return false + } + return deepEqualsCoreTests(lhs.allNullableTypes, rhs.allNullableTypes) + && deepEqualsCoreTests( + lhs.allNullableTypesWithoutRecursion, rhs.allNullableTypesWithoutRecursion) + && deepEqualsCoreTests(lhs.allTypes, rhs.allTypes) + && deepEqualsCoreTests(lhs.classList, rhs.classList) + && deepEqualsCoreTests(lhs.nullableClassList, rhs.nullableClassList) + && deepEqualsCoreTests(lhs.classMap, rhs.classMap) + && deepEqualsCoreTests(lhs.nullableClassMap, rhs.nullableClassMap) } + func hash(into hasher: inout Hasher) { - deepHashCoreTests(value: toList(), hasher: &hasher) + hasher.combine("AllClassesWrapper") + deepHashCoreTests(value: allNullableTypes, hasher: &hasher) + deepHashCoreTests(value: allNullableTypesWithoutRecursion, hasher: &hasher) + deepHashCoreTests(value: allTypes, hasher: &hasher) + deepHashCoreTests(value: classList, hasher: &hasher) + deepHashCoreTests(value: nullableClassList, hasher: &hasher) + deepHashCoreTests(value: classMap, hasher: &hasher) + deepHashCoreTests(value: nullableClassMap, hasher: &hasher) } } @@ -739,10 +987,15 @@ struct TestMessage: Hashable { ] } static func == (lhs: TestMessage, rhs: TestMessage) -> Bool { - return deepEqualsCoreTests(lhs.toList(), rhs.toList()) + if Swift.type(of: lhs) != Swift.type(of: rhs) { + return false + } + return deepEqualsCoreTests(lhs.testList, rhs.testList) } + func hash(into hasher: inout Hasher) { - deepHashCoreTests(value: toList(), hasher: &hasher) + hasher.combine("TestMessage") + deepHashCoreTests(value: testList, hasher: &hasher) } } @@ -893,6 +1146,13 @@ protocol HostIntegrationCoreApi { func echoOptionalDefault(_ aDouble: Double) throws -> Double /// Returns passed in int. func echoRequired(_ anInt: Int64) throws -> Int64 + /// Returns the result of platform-side equality check. + func areAllNullableTypesEqual(a: AllNullableTypes, b: AllNullableTypes) throws -> Bool + /// Returns the platform-side hash code for the given object. + func getAllNullableTypesHash(value: AllNullableTypes) throws -> Int64 + /// Returns the platform-side hash code for the given object. + func getAllNullableTypesWithoutRecursionHash(value: AllNullableTypesWithoutRecursion) throws + -> Int64 /// Returns the passed object, to test serialization and deserialization. func echo(_ everything: AllNullableTypes?) throws -> AllNullableTypes? /// Returns the passed object, to test serialization and deserialization. @@ -1785,6 +2045,64 @@ class HostIntegrationCoreApiSetup { } else { echoRequiredIntChannel.setMessageHandler(nil) } + /// Returns the result of platform-side equality check. + let areAllNullableTypesEqualChannel = FlutterBasicMessageChannel( + name: + "dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi.areAllNullableTypesEqual\(channelSuffix)", + binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + areAllNullableTypesEqualChannel.setMessageHandler { message, reply in + let args = message as! [Any?] + let aArg = args[0] as! AllNullableTypes + let bArg = args[1] as! AllNullableTypes + do { + let result = try api.areAllNullableTypesEqual(a: aArg, b: bArg) + reply(wrapResult(result)) + } catch { + reply(wrapError(error)) + } + } + } else { + areAllNullableTypesEqualChannel.setMessageHandler(nil) + } + /// Returns the platform-side hash code for the given object. + let getAllNullableTypesHashChannel = FlutterBasicMessageChannel( + name: + "dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi.getAllNullableTypesHash\(channelSuffix)", + binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + getAllNullableTypesHashChannel.setMessageHandler { message, reply in + let args = message as! [Any?] + let valueArg = args[0] as! AllNullableTypes + do { + let result = try api.getAllNullableTypesHash(value: valueArg) + reply(wrapResult(result)) + } catch { + reply(wrapError(error)) + } + } + } else { + getAllNullableTypesHashChannel.setMessageHandler(nil) + } + /// Returns the platform-side hash code for the given object. + let getAllNullableTypesWithoutRecursionHashChannel = FlutterBasicMessageChannel( + name: + "dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi.getAllNullableTypesWithoutRecursionHash\(channelSuffix)", + binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + getAllNullableTypesWithoutRecursionHashChannel.setMessageHandler { message, reply in + let args = message as! [Any?] + let valueArg = args[0] as! AllNullableTypesWithoutRecursion + do { + let result = try api.getAllNullableTypesWithoutRecursionHash(value: valueArg) + reply(wrapResult(result)) + } catch { + reply(wrapError(error)) + } + } + } else { + getAllNullableTypesWithoutRecursionHashChannel.setMessageHandler(nil) + } /// Returns the passed object, to test serialization and deserialization. let echoAllNullableTypesChannel = FlutterBasicMessageChannel( name: diff --git a/packages/pigeon/platform_tests/test_plugin/darwin/test_plugin/Sources/test_plugin/EventChannelTests.gen.swift b/packages/pigeon/platform_tests/test_plugin/darwin/test_plugin/Sources/test_plugin/EventChannelTests.gen.swift index 6eeace16d903..da3e19626382 100644 --- a/packages/pigeon/platform_tests/test_plugin/darwin/test_plugin/Sources/test_plugin/EventChannelTests.gen.swift +++ b/packages/pigeon/platform_tests/test_plugin/darwin/test_plugin/Sources/test_plugin/EventChannelTests.gen.swift @@ -42,6 +42,19 @@ private func nilOrValue(_ value: Any?) -> T? { return value as! T? } +private func doubleEqualsEventChannelTests(_ lhs: Double, _ rhs: Double) -> Bool { + return (lhs.isNaN && rhs.isNaN) || lhs == rhs +} + +private func doubleHashEventChannelTests(_ value: Double, _ hasher: inout Hasher) { + if value.isNaN { + hasher.combine(0x7FF8_0000_0000_0000) + } else { + // Normalize -0.0 to 0.0 + hasher.combine(value == 0 ? 0 : value) + } +} + func deepEqualsEventChannelTests(_ lhs: Any?, _ rhs: Any?) -> Bool { let cleanLhs = nilOrValue(lhs) as Any? let cleanRhs = nilOrValue(rhs) as Any? @@ -52,56 +65,90 @@ func deepEqualsEventChannelTests(_ lhs: Any?, _ rhs: Any?) -> Bool { case (nil, _), (_, nil): return false - case is (Void, Void): + case (let lhs as AnyObject, let rhs as AnyObject) where lhs === rhs: return true - case let (cleanLhsHashable, cleanRhsHashable) as (AnyHashable, AnyHashable): - return cleanLhsHashable == cleanRhsHashable + case is (Void, Void): + return true - case let (cleanLhsArray, cleanRhsArray) as ([Any?], [Any?]): - guard cleanLhsArray.count == cleanRhsArray.count else { return false } - for (index, element) in cleanLhsArray.enumerated() { - if !deepEqualsEventChannelTests(element, cleanRhsArray[index]) { + case (let lhsArray, let rhsArray) as ([Any?], [Any?]): + guard lhsArray.count == rhsArray.count else { return false } + for (index, element) in lhsArray.enumerated() { + if !deepEqualsEventChannelTests(element, rhsArray[index]) { return false } } return true - case let (cleanLhsDictionary, cleanRhsDictionary) as ([AnyHashable: Any?], [AnyHashable: Any?]): - guard cleanLhsDictionary.count == cleanRhsDictionary.count else { return false } - for (key, cleanLhsValue) in cleanLhsDictionary { - guard cleanRhsDictionary.index(forKey: key) != nil else { return false } - if !deepEqualsEventChannelTests(cleanLhsValue, cleanRhsDictionary[key]!) { + case (let lhsArray, let rhsArray) as ([Double], [Double]): + guard lhsArray.count == rhsArray.count else { return false } + for (index, element) in lhsArray.enumerated() { + if !doubleEqualsEventChannelTests(element, rhsArray[index]) { return false } } return true + case (let lhsDictionary, let rhsDictionary) as ([AnyHashable: Any?], [AnyHashable: Any?]): + guard lhsDictionary.count == rhsDictionary.count else { return false } + for (lhsKey, lhsValue) in lhsDictionary { + var found = false + for (rhsKey, rhsValue) in rhsDictionary { + if deepEqualsEventChannelTests(lhsKey, rhsKey) { + if deepEqualsEventChannelTests(lhsValue, rhsValue) { + found = true + break + } else { + return false + } + } + } + if !found { return false } + } + return true + + case (let lhs as Double, let rhs as Double): + return doubleEqualsEventChannelTests(lhs, rhs) + + case (let lhsHashable, let rhsHashable) as (AnyHashable, AnyHashable): + return lhsHashable == rhsHashable + default: - // Any other type shouldn't be able to be used with pigeon. File an issue if you find this to be untrue. return false } } func deepHashEventChannelTests(value: Any?, hasher: inout Hasher) { - if let valueList = value as? [AnyHashable] { - for item in valueList { deepHashEventChannelTests(value: item, hasher: &hasher) } - return - } - - if let valueDict = value as? [AnyHashable: AnyHashable] { - for key in valueDict.keys { - hasher.combine(key) - deepHashEventChannelTests(value: valueDict[key]!, hasher: &hasher) + let cleanValue = nilOrValue(value) as Any? + if let cleanValue = cleanValue { + if let doubleValue = cleanValue as? Double { + doubleHashEventChannelTests(doubleValue, &hasher) + } else if let valueList = cleanValue as? [Any?] { + for item in valueList { + deepHashEventChannelTests(value: item, hasher: &hasher) + } + } else if let valueList = cleanValue as? [Double] { + for item in valueList { + doubleHashEventChannelTests(item, &hasher) + } + } else if let valueDict = cleanValue as? [AnyHashable: Any?] { + var result = 0 + for (key, value) in valueDict { + var entryKeyHasher = Hasher() + deepHashEventChannelTests(value: key, hasher: &entryKeyHasher) + var entryValueHasher = Hasher() + deepHashEventChannelTests(value: value, hasher: &entryValueHasher) + result = result &+ ((entryKeyHasher.finalize() &* 31) ^ entryValueHasher.finalize()) + } + hasher.combine(result) + } else if let hashableValue = cleanValue as? AnyHashable { + hasher.combine(hashableValue) + } else { + hasher.combine(String(describing: cleanValue)) } - return - } - - if let hashableValue = value as? AnyHashable { - hasher.combine(hashableValue.hashValue) + } else { + hasher.combine(0) } - - return hasher.combine(String(describing: value)) } enum EventEnum: Int { @@ -321,13 +368,78 @@ class EventAllNullableTypes: Hashable { ] } static func == (lhs: EventAllNullableTypes, rhs: EventAllNullableTypes) -> Bool { + if Swift.type(of: lhs) != Swift.type(of: rhs) { + return false + } if lhs === rhs { return true } - return deepEqualsEventChannelTests(lhs.toList(), rhs.toList()) + return deepEqualsEventChannelTests(lhs.aNullableBool, rhs.aNullableBool) + && deepEqualsEventChannelTests(lhs.aNullableInt, rhs.aNullableInt) + && deepEqualsEventChannelTests(lhs.aNullableInt64, rhs.aNullableInt64) + && deepEqualsEventChannelTests(lhs.aNullableDouble, rhs.aNullableDouble) + && deepEqualsEventChannelTests(lhs.aNullableByteArray, rhs.aNullableByteArray) + && deepEqualsEventChannelTests(lhs.aNullable4ByteArray, rhs.aNullable4ByteArray) + && deepEqualsEventChannelTests(lhs.aNullable8ByteArray, rhs.aNullable8ByteArray) + && deepEqualsEventChannelTests(lhs.aNullableFloatArray, rhs.aNullableFloatArray) + && deepEqualsEventChannelTests(lhs.aNullableEnum, rhs.aNullableEnum) + && deepEqualsEventChannelTests(lhs.anotherNullableEnum, rhs.anotherNullableEnum) + && deepEqualsEventChannelTests(lhs.aNullableString, rhs.aNullableString) + && deepEqualsEventChannelTests(lhs.aNullableObject, rhs.aNullableObject) + && deepEqualsEventChannelTests(lhs.allNullableTypes, rhs.allNullableTypes) + && deepEqualsEventChannelTests(lhs.list, rhs.list) + && deepEqualsEventChannelTests(lhs.stringList, rhs.stringList) + && deepEqualsEventChannelTests(lhs.intList, rhs.intList) + && deepEqualsEventChannelTests(lhs.doubleList, rhs.doubleList) + && deepEqualsEventChannelTests(lhs.boolList, rhs.boolList) + && deepEqualsEventChannelTests(lhs.enumList, rhs.enumList) + && deepEqualsEventChannelTests(lhs.objectList, rhs.objectList) + && deepEqualsEventChannelTests(lhs.listList, rhs.listList) + && deepEqualsEventChannelTests(lhs.mapList, rhs.mapList) + && deepEqualsEventChannelTests(lhs.recursiveClassList, rhs.recursiveClassList) + && deepEqualsEventChannelTests(lhs.map, rhs.map) + && deepEqualsEventChannelTests(lhs.stringMap, rhs.stringMap) + && deepEqualsEventChannelTests(lhs.intMap, rhs.intMap) + && deepEqualsEventChannelTests(lhs.enumMap, rhs.enumMap) + && deepEqualsEventChannelTests(lhs.objectMap, rhs.objectMap) + && deepEqualsEventChannelTests(lhs.listMap, rhs.listMap) + && deepEqualsEventChannelTests(lhs.mapMap, rhs.mapMap) + && deepEqualsEventChannelTests(lhs.recursiveClassMap, rhs.recursiveClassMap) } + func hash(into hasher: inout Hasher) { - deepHashEventChannelTests(value: toList(), hasher: &hasher) + hasher.combine("EventAllNullableTypes") + deepHashEventChannelTests(value: aNullableBool, hasher: &hasher) + deepHashEventChannelTests(value: aNullableInt, hasher: &hasher) + deepHashEventChannelTests(value: aNullableInt64, hasher: &hasher) + deepHashEventChannelTests(value: aNullableDouble, hasher: &hasher) + deepHashEventChannelTests(value: aNullableByteArray, hasher: &hasher) + deepHashEventChannelTests(value: aNullable4ByteArray, hasher: &hasher) + deepHashEventChannelTests(value: aNullable8ByteArray, hasher: &hasher) + deepHashEventChannelTests(value: aNullableFloatArray, hasher: &hasher) + deepHashEventChannelTests(value: aNullableEnum, hasher: &hasher) + deepHashEventChannelTests(value: anotherNullableEnum, hasher: &hasher) + deepHashEventChannelTests(value: aNullableString, hasher: &hasher) + deepHashEventChannelTests(value: aNullableObject, hasher: &hasher) + deepHashEventChannelTests(value: allNullableTypes, hasher: &hasher) + deepHashEventChannelTests(value: list, hasher: &hasher) + deepHashEventChannelTests(value: stringList, hasher: &hasher) + deepHashEventChannelTests(value: intList, hasher: &hasher) + deepHashEventChannelTests(value: doubleList, hasher: &hasher) + deepHashEventChannelTests(value: boolList, hasher: &hasher) + deepHashEventChannelTests(value: enumList, hasher: &hasher) + deepHashEventChannelTests(value: objectList, hasher: &hasher) + deepHashEventChannelTests(value: listList, hasher: &hasher) + deepHashEventChannelTests(value: mapList, hasher: &hasher) + deepHashEventChannelTests(value: recursiveClassList, hasher: &hasher) + deepHashEventChannelTests(value: map, hasher: &hasher) + deepHashEventChannelTests(value: stringMap, hasher: &hasher) + deepHashEventChannelTests(value: intMap, hasher: &hasher) + deepHashEventChannelTests(value: enumMap, hasher: &hasher) + deepHashEventChannelTests(value: objectMap, hasher: &hasher) + deepHashEventChannelTests(value: listMap, hasher: &hasher) + deepHashEventChannelTests(value: mapMap, hasher: &hasher) + deepHashEventChannelTests(value: recursiveClassMap, hasher: &hasher) } } @@ -355,10 +467,15 @@ struct IntEvent: PlatformEvent { ] } static func == (lhs: IntEvent, rhs: IntEvent) -> Bool { - return deepEqualsEventChannelTests(lhs.toList(), rhs.toList()) + if Swift.type(of: lhs) != Swift.type(of: rhs) { + return false + } + return deepEqualsEventChannelTests(lhs.value, rhs.value) } + func hash(into hasher: inout Hasher) { - deepHashEventChannelTests(value: toList(), hasher: &hasher) + hasher.combine("IntEvent") + deepHashEventChannelTests(value: value, hasher: &hasher) } } @@ -380,10 +497,15 @@ struct StringEvent: PlatformEvent { ] } static func == (lhs: StringEvent, rhs: StringEvent) -> Bool { - return deepEqualsEventChannelTests(lhs.toList(), rhs.toList()) + if Swift.type(of: lhs) != Swift.type(of: rhs) { + return false + } + return deepEqualsEventChannelTests(lhs.value, rhs.value) } + func hash(into hasher: inout Hasher) { - deepHashEventChannelTests(value: toList(), hasher: &hasher) + hasher.combine("StringEvent") + deepHashEventChannelTests(value: value, hasher: &hasher) } } @@ -405,10 +527,15 @@ struct BoolEvent: PlatformEvent { ] } static func == (lhs: BoolEvent, rhs: BoolEvent) -> Bool { - return deepEqualsEventChannelTests(lhs.toList(), rhs.toList()) + if Swift.type(of: lhs) != Swift.type(of: rhs) { + return false + } + return deepEqualsEventChannelTests(lhs.value, rhs.value) } + func hash(into hasher: inout Hasher) { - deepHashEventChannelTests(value: toList(), hasher: &hasher) + hasher.combine("BoolEvent") + deepHashEventChannelTests(value: value, hasher: &hasher) } } @@ -430,10 +557,15 @@ struct DoubleEvent: PlatformEvent { ] } static func == (lhs: DoubleEvent, rhs: DoubleEvent) -> Bool { - return deepEqualsEventChannelTests(lhs.toList(), rhs.toList()) + if Swift.type(of: lhs) != Swift.type(of: rhs) { + return false + } + return deepEqualsEventChannelTests(lhs.value, rhs.value) } + func hash(into hasher: inout Hasher) { - deepHashEventChannelTests(value: toList(), hasher: &hasher) + hasher.combine("DoubleEvent") + deepHashEventChannelTests(value: value, hasher: &hasher) } } @@ -455,10 +587,15 @@ struct ObjectsEvent: PlatformEvent { ] } static func == (lhs: ObjectsEvent, rhs: ObjectsEvent) -> Bool { - return deepEqualsEventChannelTests(lhs.toList(), rhs.toList()) + if Swift.type(of: lhs) != Swift.type(of: rhs) { + return false + } + return deepEqualsEventChannelTests(lhs.value, rhs.value) } + func hash(into hasher: inout Hasher) { - deepHashEventChannelTests(value: toList(), hasher: &hasher) + hasher.combine("ObjectsEvent") + deepHashEventChannelTests(value: value, hasher: &hasher) } } @@ -480,10 +617,15 @@ struct EnumEvent: PlatformEvent { ] } static func == (lhs: EnumEvent, rhs: EnumEvent) -> Bool { - return deepEqualsEventChannelTests(lhs.toList(), rhs.toList()) + if Swift.type(of: lhs) != Swift.type(of: rhs) { + return false + } + return deepEqualsEventChannelTests(lhs.value, rhs.value) } + func hash(into hasher: inout Hasher) { - deepHashEventChannelTests(value: toList(), hasher: &hasher) + hasher.combine("EnumEvent") + deepHashEventChannelTests(value: value, hasher: &hasher) } } @@ -505,10 +647,15 @@ struct ClassEvent: PlatformEvent { ] } static func == (lhs: ClassEvent, rhs: ClassEvent) -> Bool { - return deepEqualsEventChannelTests(lhs.toList(), rhs.toList()) + if Swift.type(of: lhs) != Swift.type(of: rhs) { + return false + } + return deepEqualsEventChannelTests(lhs.value, rhs.value) } + func hash(into hasher: inout Hasher) { - deepHashEventChannelTests(value: toList(), hasher: &hasher) + hasher.combine("ClassEvent") + deepHashEventChannelTests(value: value, hasher: &hasher) } } diff --git a/packages/pigeon/platform_tests/test_plugin/darwin/test_plugin/Sources/test_plugin/ProxyApiTests.gen.swift b/packages/pigeon/platform_tests/test_plugin/darwin/test_plugin/Sources/test_plugin/ProxyApiTests.gen.swift index 3e392185d448..5eb4b81803ad 100644 --- a/packages/pigeon/platform_tests/test_plugin/darwin/test_plugin/Sources/test_plugin/ProxyApiTests.gen.swift +++ b/packages/pigeon/platform_tests/test_plugin/darwin/test_plugin/Sources/test_plugin/ProxyApiTests.gen.swift @@ -54,7 +54,7 @@ private func wrapError(_ error: Any) -> [Any?] { } return [ "\(error)", - "\(type(of: error))", + "\(Swift.type(of: error))", "Stacktrace: \(Thread.callStackSymbols)", ] } diff --git a/packages/pigeon/platform_tests/test_plugin/darwin/test_plugin/Sources/test_plugin/TestPlugin.swift b/packages/pigeon/platform_tests/test_plugin/darwin/test_plugin/Sources/test_plugin/TestPlugin.swift index fec488571752..89d25d32f58e 100644 --- a/packages/pigeon/platform_tests/test_plugin/darwin/test_plugin/Sources/test_plugin/TestPlugin.swift +++ b/packages/pigeon/platform_tests/test_plugin/darwin/test_plugin/Sources/test_plugin/TestPlugin.swift @@ -70,6 +70,22 @@ public class TestPlugin: NSObject, FlutterPlugin, HostIntegrationCoreApi { func echo(_ everything: AllNullableTypes?) -> AllNullableTypes? { return everything } + + func areAllNullableTypesEqual(a: AllNullableTypes, b: AllNullableTypes) -> Bool { + return a == b + } + + func getAllNullableTypesHash(value: AllNullableTypes) -> Int64 { + var hasher = Hasher() + value.hash(into: &hasher) + return Int64(hasher.finalize()) + } + + func getAllNullableTypesWithoutRecursionHash(value: AllNullableTypesWithoutRecursion) -> Int64 { + var hasher = Hasher() + value.hash(into: &hasher) + return Int64(hasher.finalize()) + } func echo(_ everything: AllNullableTypesWithoutRecursion?) throws -> AllNullableTypesWithoutRecursion? { diff --git a/packages/pigeon/platform_tests/test_plugin/example/ios/RunnerTests/AllDatatypesTests.swift b/packages/pigeon/platform_tests/test_plugin/example/ios/RunnerTests/AllDatatypesTests.swift index bd9ab4ae67e2..e855f673fd29 100644 --- a/packages/pigeon/platform_tests/test_plugin/example/ios/RunnerTests/AllDatatypesTests.swift +++ b/packages/pigeon/platform_tests/test_plugin/example/ios/RunnerTests/AllDatatypesTests.swift @@ -187,4 +187,141 @@ struct AllDatatypesTests { withMapInList == withMatchingMapInList, "Instances with equivalent nested maps in lists should be equal") } + + @Test + func equalityWithNaN() throws { + let list = [Double.nan] + let map: [Int64: Double?] = [1: Double.nan] + let a = AllNullableTypes( + aNullableDouble: Double.nan, + doubleList: list, + recursiveClassList: [AllNullableTypes(aNullableDouble: Double.nan)], + map: map + ) + let b = AllNullableTypes( + aNullableDouble: Double.nan, + doubleList: list, + recursiveClassList: [AllNullableTypes(aNullableDouble: Double.nan)], + map: map + ) + #expect(a == b) + } + + @Test + func hashWithNaN() throws { + let a = AllNullableTypes(aNullableDouble: Double.nan) + let b = AllNullableTypes(aNullableDouble: Double.nan) + + var hasherA = Hasher() + a.hash(into: &hasherA) + let hashA = hasherA.finalize() + + var hasherB = Hasher() + b.hash(into: &hasherB) + let hashB = hasherB.finalize() + + #expect(hashA == hashB) + } + + @Test + func structEquality() { + let a = AllNullableTypesWithoutRecursion(aNullableInt: 1) + let b = AllNullableTypesWithoutRecursion(aNullableInt: 1) + let c = AllNullableTypesWithoutRecursion(aNullableInt: 2) + #expect(a == b) + #expect(a != c) + } + + @Test + func crossTypeEquality() { + let a = AllNullableTypes(aNullableInt: 1) + let b = AllNullableTypesWithoutRecursion(aNullableInt: 1) + // They are different types, so they shouldn't be equal even if we cast to Any + let anyA: Any = a + let anyB: Any = b + #expect(!(anyA as? AllNullableTypesWithoutRecursion == b)) + #expect(!(anyB as? AllNullableTypes == a)) + } + + @Test + func typedDataEquality() { + let data1 = "1234".data(using: .utf8)! + let data2 = "1234".data(using: .utf8)! + // Ensure they are different instances in memory if possible, + // though Data in Swift is a value type. + // FlutterStandardTypedData is a class. + let a = AllNullableTypes(aNullableByteArray: FlutterStandardTypedData(bytes: data1)) + let c = a + c.aNullableByteArray = FlutterStandardTypedData(bytes: data2) + + #expect(a == c) + } + + @Test + func signedZeroEquality() { + let a = AllNullableTypes(aNullableDouble: 0.0) + let b = AllNullableTypes(aNullableDouble: -0.0) + #expect(a == b) + + var hasherA = Hasher() + a.hash(into: &hasherA) + let hashA = hasherA.finalize() + + var hasherB = Hasher() + b.hash(into: &hasherB) + let hashB = hasherB.finalize() + + #expect(hashA == hashB) + } + + @Test + func nestedZeroListEquality() { + let a = AllNullableTypes(doubleList: [0.0]) + let b = AllNullableTypes(doubleList: [-0.0]) + #expect(a == b) + + var hasherA = Hasher() + a.hash(into: &hasherA) + let hashA = hasherA.finalize() + + var hasherB = Hasher() + b.hash(into: &hasherB) + let hashB = hasherB.finalize() + + #expect(hashA == hashB) + } + + @Test + func zeroMapKeyEquality() { + let a = AllNullableTypes(map: [0.0: "a"]) + let b = AllNullableTypes(map: [-0.0: "a"]) + #expect(a == b) + + var hasherA = Hasher() + a.hash(into: &hasherA) + let hashA = hasherA.finalize() + + var hasherB = Hasher() + b.hash(into: &hasherB) + let hashB = hasherB.finalize() + + #expect(hashA == hashB) + } + + @Test + func zeroMapValueEquality() { + let a = AllNullableTypes(map: ["a": 0.0]) + let b = AllNullableTypes(map: ["a": -0.0]) + #expect(a == b) + + var hasherA = Hasher() + a.hash(into: &hasherA) + let hashA = hasherA.finalize() + + var hasherB = Hasher() + b.hash(into: &hasherB) + let hashB = hasherB.finalize() + + #expect(hashA == hashB) + } } diff --git a/packages/pigeon/platform_tests/test_plugin/example/ios/RunnerTests/MultipleArityTests.swift b/packages/pigeon/platform_tests/test_plugin/example/ios/RunnerTests/MultipleArityTests.swift index dec835076052..7a87a0052231 100644 --- a/packages/pigeon/platform_tests/test_plugin/example/ios/RunnerTests/MultipleArityTests.swift +++ b/packages/pigeon/platform_tests/test_plugin/example/ios/RunnerTests/MultipleArityTests.swift @@ -15,7 +15,7 @@ class MockMultipleArityHostApi: MultipleArityHostApi { @MainActor struct MultipleArityTests { - var codec = FlutterStandardMessageCodec.sharedInstance() + let codec = FlutterStandardMessageCodec.sharedInstance() @Test func simpleHost() async throws { diff --git a/packages/pigeon/platform_tests/test_plugin/example/ios/RunnerTests/NonNullFieldsTest.swift b/packages/pigeon/platform_tests/test_plugin/example/ios/RunnerTests/NonNullFieldsTest.swift index 927117fa0874..bb06e1bbf2b2 100644 --- a/packages/pigeon/platform_tests/test_plugin/example/ios/RunnerTests/NonNullFieldsTest.swift +++ b/packages/pigeon/platform_tests/test_plugin/example/ios/RunnerTests/NonNullFieldsTest.swift @@ -12,4 +12,15 @@ struct NonNullFieldsTests { let request = NonNullFieldSearchRequest(query: "hello") #expect(request.query == "hello") } + + @Test + func testEquality() { + let request1 = NonNullFieldSearchRequest(query: "hello") + let request2 = NonNullFieldSearchRequest(query: "hello") + let request3 = NonNullFieldSearchRequest(query: "world") + + #expect(request1 == request2) + #expect(request1 != request3) + #expect(request1.hashValue == request2.hashValue) + } } diff --git a/packages/pigeon/platform_tests/test_plugin/example/ios/RunnerTests/NullableReturnsTests.swift b/packages/pigeon/platform_tests/test_plugin/example/ios/RunnerTests/NullableReturnsTests.swift index 6d12dbae93ca..e2925038f6b9 100644 --- a/packages/pigeon/platform_tests/test_plugin/example/ios/RunnerTests/NullableReturnsTests.swift +++ b/packages/pigeon/platform_tests/test_plugin/example/ios/RunnerTests/NullableReturnsTests.swift @@ -20,7 +20,7 @@ class MockNullableArgHostApi: NullableArgHostApi { @MainActor struct NullableReturnsTests { - var codec = FlutterStandardMessageCodec.sharedInstance() + let codec = FlutterStandardMessageCodec.sharedInstance() @Test func nullableParameterWithFlutterApi() async throws { diff --git a/packages/pigeon/platform_tests/test_plugin/example/ios/RunnerTests/PrimitiveTests.swift b/packages/pigeon/platform_tests/test_plugin/example/ios/RunnerTests/PrimitiveTests.swift index 62b300b9ab5b..0a3228e86eaf 100644 --- a/packages/pigeon/platform_tests/test_plugin/example/ios/RunnerTests/PrimitiveTests.swift +++ b/packages/pigeon/platform_tests/test_plugin/example/ios/RunnerTests/PrimitiveTests.swift @@ -21,7 +21,7 @@ class MockPrimitiveHostApi: PrimitiveHostApi { @MainActor struct PrimitiveTests { - var codec = FlutterStandardMessageCodec.sharedInstance() + let codec = FlutterStandardMessageCodec.sharedInstance() @Test func intPrimitiveHost() async throws { diff --git a/packages/pigeon/platform_tests/test_plugin/linux/CMakeLists.txt b/packages/pigeon/platform_tests/test_plugin/linux/CMakeLists.txt index 3d2845f8d3e4..c2cdee101723 100644 --- a/packages/pigeon/platform_tests/test_plugin/linux/CMakeLists.txt +++ b/packages/pigeon/platform_tests/test_plugin/linux/CMakeLists.txt @@ -100,6 +100,7 @@ add_executable(${TEST_RUNNER} test/nullable_returns_test.cc test/null_fields_test.cc test/primitive_test.cc + test/equality_test.cc # Test utilities. test/utils/fake_host_messenger.cc test/utils/fake_host_messenger.h diff --git a/packages/pigeon/platform_tests/test_plugin/linux/pigeon/core_tests.gen.cc b/packages/pigeon/platform_tests/test_plugin/linux/pigeon/core_tests.gen.cc index ae3763bf5e0e..023cd1ed85db 100644 --- a/packages/pigeon/platform_tests/test_plugin/linux/pigeon/core_tests.gen.cc +++ b/packages/pigeon/platform_tests/test_plugin/linux/pigeon/core_tests.gen.cc @@ -7,6 +7,197 @@ #include "core_tests.gen.h" +#include + +#include +static guint G_GNUC_UNUSED flpigeon_hash_double(double v) { + if (std::isnan(v)) { + return static_cast(0x7FF80000); + } + if (v == 0.0) { + v = 0.0; + } + union { + double d; + uint64_t u; + } u; + u.d = v; + return static_cast(u.u ^ (u.u >> 32)); +} +static gboolean G_GNUC_UNUSED flpigeon_equals_double(double a, double b) { + return (a == b) || (std::isnan(a) && std::isnan(b)); +} +static gboolean G_GNUC_UNUSED flpigeon_deep_equals(FlValue* a, FlValue* b) { + if (a == b) { + return TRUE; + } + if (a == nullptr || b == nullptr) { + return FALSE; + } + if (fl_value_get_type(a) != fl_value_get_type(b)) { + return FALSE; + } + switch (fl_value_get_type(a)) { + case FL_VALUE_TYPE_NULL: + return TRUE; + case FL_VALUE_TYPE_BOOL: + return fl_value_get_bool(a) == fl_value_get_bool(b); + case FL_VALUE_TYPE_INT: + return fl_value_get_int(a) == fl_value_get_int(b); + case FL_VALUE_TYPE_FLOAT: { + return flpigeon_equals_double(fl_value_get_float(a), + fl_value_get_float(b)); + } + case FL_VALUE_TYPE_STRING: + return g_strcmp0(fl_value_get_string(a), fl_value_get_string(b)) == 0; + case FL_VALUE_TYPE_UINT8_LIST: + return fl_value_get_length(a) == fl_value_get_length(b) && + memcmp(fl_value_get_uint8_list(a), fl_value_get_uint8_list(b), + fl_value_get_length(a)) == 0; + case FL_VALUE_TYPE_INT32_LIST: + return fl_value_get_length(a) == fl_value_get_length(b) && + memcmp(fl_value_get_int32_list(a), fl_value_get_int32_list(b), + fl_value_get_length(a) * sizeof(int32_t)) == 0; + case FL_VALUE_TYPE_INT64_LIST: + return fl_value_get_length(a) == fl_value_get_length(b) && + memcmp(fl_value_get_int64_list(a), fl_value_get_int64_list(b), + fl_value_get_length(a) * sizeof(int64_t)) == 0; + case FL_VALUE_TYPE_FLOAT_LIST: { + size_t len = fl_value_get_length(a); + if (len != fl_value_get_length(b)) { + return FALSE; + } + const double* a_data = fl_value_get_float_list(a); + const double* b_data = fl_value_get_float_list(b); + for (size_t i = 0; i < len; i++) { + if (!flpigeon_equals_double(a_data[i], b_data[i])) { + return FALSE; + } + } + return TRUE; + } + case FL_VALUE_TYPE_LIST: { + size_t len = fl_value_get_length(a); + if (len != fl_value_get_length(b)) { + return FALSE; + } + for (size_t i = 0; i < len; i++) { + if (!flpigeon_deep_equals(fl_value_get_list_value(a, i), + fl_value_get_list_value(b, i))) { + return FALSE; + } + } + return TRUE; + } + case FL_VALUE_TYPE_MAP: { + size_t len = fl_value_get_length(a); + if (len != fl_value_get_length(b)) { + return FALSE; + } + for (size_t i = 0; i < len; i++) { + FlValue* key = fl_value_get_map_key(a, i); + FlValue* val = fl_value_get_map_value(a, i); + gboolean found = FALSE; + for (size_t j = 0; j < len; j++) { + FlValue* b_key = fl_value_get_map_key(b, j); + if (flpigeon_deep_equals(key, b_key)) { + FlValue* b_val = fl_value_get_map_value(b, j); + if (flpigeon_deep_equals(val, b_val)) { + found = TRUE; + break; + } else { + return FALSE; + } + } + } + if (!found) { + return FALSE; + } + } + return TRUE; + } + default: + return FALSE; + } + return FALSE; +} +static guint G_GNUC_UNUSED flpigeon_deep_hash(FlValue* value) { + if (value == nullptr) { + return 0; + } + switch (fl_value_get_type(value)) { + case FL_VALUE_TYPE_NULL: + return 0; + case FL_VALUE_TYPE_BOOL: + return fl_value_get_bool(value) ? 1231 : 1237; + case FL_VALUE_TYPE_INT: { + int64_t v = fl_value_get_int(value); + return static_cast(v ^ (v >> 32)); + } + case FL_VALUE_TYPE_FLOAT: + return flpigeon_hash_double(fl_value_get_float(value)); + case FL_VALUE_TYPE_STRING: + return g_str_hash(fl_value_get_string(value)); + case FL_VALUE_TYPE_UINT8_LIST: { + guint result = 1; + size_t len = fl_value_get_length(value); + const uint8_t* data = fl_value_get_uint8_list(value); + for (size_t i = 0; i < len; i++) { + result = result * 31 + data[i]; + } + return result; + } + case FL_VALUE_TYPE_INT32_LIST: { + guint result = 1; + size_t len = fl_value_get_length(value); + const int32_t* data = fl_value_get_int32_list(value); + for (size_t i = 0; i < len; i++) { + result = result * 31 + static_cast(data[i]); + } + return result; + } + case FL_VALUE_TYPE_INT64_LIST: { + guint result = 1; + size_t len = fl_value_get_length(value); + const int64_t* data = fl_value_get_int64_list(value); + for (size_t i = 0; i < len; i++) { + result = result * 31 + static_cast(data[i] ^ (data[i] >> 32)); + } + return result; + } + case FL_VALUE_TYPE_FLOAT_LIST: { + guint result = 1; + size_t len = fl_value_get_length(value); + const double* data = fl_value_get_float_list(value); + for (size_t i = 0; i < len; i++) { + result = result * 31 + flpigeon_hash_double(data[i]); + } + return result; + } + case FL_VALUE_TYPE_LIST: { + guint result = 1; + size_t len = fl_value_get_length(value); + for (size_t i = 0; i < len; i++) { + result = + result * 31 + flpigeon_deep_hash(fl_value_get_list_value(value, i)); + } + return result; + } + case FL_VALUE_TYPE_MAP: { + guint result = 0; + size_t len = fl_value_get_length(value); + for (size_t i = 0; i < len; i++) { + result += ((flpigeon_deep_hash(fl_value_get_map_key(value, i)) * 31) ^ + flpigeon_deep_hash(fl_value_get_map_value(value, i))); + } + return result; + } + default: + return static_cast(fl_value_get_type(value)); + } + return 0; +} + struct _CoreTestsPigeonTestUnusedClass { GObject parent_instance; @@ -69,6 +260,28 @@ core_tests_pigeon_test_unused_class_new_from_list(FlValue* values) { return core_tests_pigeon_test_unused_class_new(a_field); } +gboolean core_tests_pigeon_test_unused_class_equals( + CoreTestsPigeonTestUnusedClass* a, CoreTestsPigeonTestUnusedClass* b) { + if (a == b) { + return TRUE; + } + if (a == nullptr || b == nullptr) { + return FALSE; + } + if (!flpigeon_deep_equals(a->a_field, b->a_field)) { + return FALSE; + } + return TRUE; +} + +guint core_tests_pigeon_test_unused_class_hash( + CoreTestsPigeonTestUnusedClass* self) { + g_return_val_if_fail(CORE_TESTS_PIGEON_TEST_IS_UNUSED_CLASS(self), 0); + guint result = 0; + result = result * 31 + flpigeon_deep_hash(self->a_field); + return result; +} + struct _CoreTestsPigeonTestAllTypes { GObject parent_instance; @@ -497,6 +710,205 @@ core_tests_pigeon_test_all_types_new_from_list(FlValue* values) { object_map, list_map, map_map); } +gboolean core_tests_pigeon_test_all_types_equals( + CoreTestsPigeonTestAllTypes* a, CoreTestsPigeonTestAllTypes* b) { + if (a == b) { + return TRUE; + } + if (a == nullptr || b == nullptr) { + return FALSE; + } + if (a->a_bool != b->a_bool) { + return FALSE; + } + if (a->an_int != b->an_int) { + return FALSE; + } + if (a->an_int64 != b->an_int64) { + return FALSE; + } + if (!flpigeon_equals_double(a->a_double, b->a_double)) { + return FALSE; + } + if (a->a_byte_array != b->a_byte_array) { + if (a->a_byte_array == nullptr || b->a_byte_array == nullptr) { + return FALSE; + } + if (a->a_byte_array_length != b->a_byte_array_length) { + return FALSE; + } + if (memcmp(a->a_byte_array, b->a_byte_array, + a->a_byte_array_length * sizeof(uint8_t)) != 0) { + return FALSE; + } + } + if (a->a4_byte_array != b->a4_byte_array) { + if (a->a4_byte_array == nullptr || b->a4_byte_array == nullptr) { + return FALSE; + } + if (a->a4_byte_array_length != b->a4_byte_array_length) { + return FALSE; + } + if (memcmp(a->a4_byte_array, b->a4_byte_array, + a->a4_byte_array_length * sizeof(int32_t)) != 0) { + return FALSE; + } + } + if (a->a8_byte_array != b->a8_byte_array) { + if (a->a8_byte_array == nullptr || b->a8_byte_array == nullptr) { + return FALSE; + } + if (a->a8_byte_array_length != b->a8_byte_array_length) { + return FALSE; + } + if (memcmp(a->a8_byte_array, b->a8_byte_array, + a->a8_byte_array_length * sizeof(int64_t)) != 0) { + return FALSE; + } + } + if (a->a_float_array != b->a_float_array) { + if (a->a_float_array == nullptr || b->a_float_array == nullptr) { + return FALSE; + } + if (a->a_float_array_length != b->a_float_array_length) { + return FALSE; + } + for (size_t i = 0; i < a->a_float_array_length; i++) { + if (!flpigeon_equals_double(a->a_float_array[i], b->a_float_array[i])) { + return FALSE; + } + } + } + if (a->an_enum != b->an_enum) { + return FALSE; + } + if (a->another_enum != b->another_enum) { + return FALSE; + } + if (g_strcmp0(a->a_string, b->a_string) != 0) { + return FALSE; + } + if (!flpigeon_deep_equals(a->an_object, b->an_object)) { + return FALSE; + } + if (!flpigeon_deep_equals(a->list, b->list)) { + return FALSE; + } + if (!flpigeon_deep_equals(a->string_list, b->string_list)) { + return FALSE; + } + if (!flpigeon_deep_equals(a->int_list, b->int_list)) { + return FALSE; + } + if (!flpigeon_deep_equals(a->double_list, b->double_list)) { + return FALSE; + } + if (!flpigeon_deep_equals(a->bool_list, b->bool_list)) { + return FALSE; + } + if (!flpigeon_deep_equals(a->enum_list, b->enum_list)) { + return FALSE; + } + if (!flpigeon_deep_equals(a->object_list, b->object_list)) { + return FALSE; + } + if (!flpigeon_deep_equals(a->list_list, b->list_list)) { + return FALSE; + } + if (!flpigeon_deep_equals(a->map_list, b->map_list)) { + return FALSE; + } + if (!flpigeon_deep_equals(a->map, b->map)) { + return FALSE; + } + if (!flpigeon_deep_equals(a->string_map, b->string_map)) { + return FALSE; + } + if (!flpigeon_deep_equals(a->int_map, b->int_map)) { + return FALSE; + } + if (!flpigeon_deep_equals(a->enum_map, b->enum_map)) { + return FALSE; + } + if (!flpigeon_deep_equals(a->object_map, b->object_map)) { + return FALSE; + } + if (!flpigeon_deep_equals(a->list_map, b->list_map)) { + return FALSE; + } + if (!flpigeon_deep_equals(a->map_map, b->map_map)) { + return FALSE; + } + return TRUE; +} + +guint core_tests_pigeon_test_all_types_hash(CoreTestsPigeonTestAllTypes* self) { + g_return_val_if_fail(CORE_TESTS_PIGEON_TEST_IS_ALL_TYPES(self), 0); + guint result = 0; + result = result * 31 + static_cast(self->a_bool); + result = result * 31 + static_cast(self->an_int); + result = result * 31 + static_cast(self->an_int64); + result = result * 31 + flpigeon_hash_double(self->a_double); + { + size_t len = self->a_byte_array_length; + const uint8_t* data = self->a_byte_array; + if (data != nullptr) { + for (size_t i = 0; i < len; i++) { + result = result * 31 + static_cast(data[i]); + } + } + } + { + size_t len = self->a4_byte_array_length; + const int32_t* data = self->a4_byte_array; + if (data != nullptr) { + for (size_t i = 0; i < len; i++) { + result = result * 31 + static_cast(data[i]); + } + } + } + { + size_t len = self->a8_byte_array_length; + const int64_t* data = self->a8_byte_array; + if (data != nullptr) { + for (size_t i = 0; i < len; i++) { + result = result * 31 + static_cast(data[i] ^ (data[i] >> 32)); + } + } + } + { + size_t len = self->a_float_array_length; + const double* data = self->a_float_array; + if (data != nullptr) { + for (size_t i = 0; i < len; i++) { + result = result * 31 + flpigeon_hash_double(data[i]); + } + } + } + result = result * 31 + static_cast(self->an_enum); + result = result * 31 + static_cast(self->another_enum); + result = result * 31 + + (self->a_string != nullptr ? g_str_hash(self->a_string) : 0); + result = result * 31 + flpigeon_deep_hash(self->an_object); + result = result * 31 + flpigeon_deep_hash(self->list); + result = result * 31 + flpigeon_deep_hash(self->string_list); + result = result * 31 + flpigeon_deep_hash(self->int_list); + result = result * 31 + flpigeon_deep_hash(self->double_list); + result = result * 31 + flpigeon_deep_hash(self->bool_list); + result = result * 31 + flpigeon_deep_hash(self->enum_list); + result = result * 31 + flpigeon_deep_hash(self->object_list); + result = result * 31 + flpigeon_deep_hash(self->list_list); + result = result * 31 + flpigeon_deep_hash(self->map_list); + result = result * 31 + flpigeon_deep_hash(self->map); + result = result * 31 + flpigeon_deep_hash(self->string_map); + result = result * 31 + flpigeon_deep_hash(self->int_map); + result = result * 31 + flpigeon_deep_hash(self->enum_map); + result = result * 31 + flpigeon_deep_hash(self->object_map); + result = result * 31 + flpigeon_deep_hash(self->list_map); + result = result * 31 + flpigeon_deep_hash(self->map_map); + return result; +} + struct _CoreTestsPigeonTestAllNullableTypes { GObject parent_instance; @@ -1331,6 +1743,264 @@ core_tests_pigeon_test_all_nullable_types_new_from_list(FlValue* values) { recursive_class_map); } +gboolean core_tests_pigeon_test_all_nullable_types_equals( + CoreTestsPigeonTestAllNullableTypes* a, + CoreTestsPigeonTestAllNullableTypes* b) { + if (a == b) { + return TRUE; + } + if (a == nullptr || b == nullptr) { + return FALSE; + } + if ((a->a_nullable_bool == nullptr) != (b->a_nullable_bool == nullptr)) { + return FALSE; + } + if (a->a_nullable_bool != nullptr && + *a->a_nullable_bool != *b->a_nullable_bool) { + return FALSE; + } + if ((a->a_nullable_int == nullptr) != (b->a_nullable_int == nullptr)) { + return FALSE; + } + if (a->a_nullable_int != nullptr && + *a->a_nullable_int != *b->a_nullable_int) { + return FALSE; + } + if ((a->a_nullable_int64 == nullptr) != (b->a_nullable_int64 == nullptr)) { + return FALSE; + } + if (a->a_nullable_int64 != nullptr && + *a->a_nullable_int64 != *b->a_nullable_int64) { + return FALSE; + } + if ((a->a_nullable_double == nullptr) != (b->a_nullable_double == nullptr)) { + return FALSE; + } + if (a->a_nullable_double != nullptr && + !flpigeon_equals_double(*a->a_nullable_double, *b->a_nullable_double)) { + return FALSE; + } + if (a->a_nullable_byte_array != b->a_nullable_byte_array) { + if (a->a_nullable_byte_array == nullptr || + b->a_nullable_byte_array == nullptr) { + return FALSE; + } + if (a->a_nullable_byte_array_length != b->a_nullable_byte_array_length) { + return FALSE; + } + if (memcmp(a->a_nullable_byte_array, b->a_nullable_byte_array, + a->a_nullable_byte_array_length * sizeof(uint8_t)) != 0) { + return FALSE; + } + } + if (a->a_nullable4_byte_array != b->a_nullable4_byte_array) { + if (a->a_nullable4_byte_array == nullptr || + b->a_nullable4_byte_array == nullptr) { + return FALSE; + } + if (a->a_nullable4_byte_array_length != b->a_nullable4_byte_array_length) { + return FALSE; + } + if (memcmp(a->a_nullable4_byte_array, b->a_nullable4_byte_array, + a->a_nullable4_byte_array_length * sizeof(int32_t)) != 0) { + return FALSE; + } + } + if (a->a_nullable8_byte_array != b->a_nullable8_byte_array) { + if (a->a_nullable8_byte_array == nullptr || + b->a_nullable8_byte_array == nullptr) { + return FALSE; + } + if (a->a_nullable8_byte_array_length != b->a_nullable8_byte_array_length) { + return FALSE; + } + if (memcmp(a->a_nullable8_byte_array, b->a_nullable8_byte_array, + a->a_nullable8_byte_array_length * sizeof(int64_t)) != 0) { + return FALSE; + } + } + if (a->a_nullable_float_array != b->a_nullable_float_array) { + if (a->a_nullable_float_array == nullptr || + b->a_nullable_float_array == nullptr) { + return FALSE; + } + if (a->a_nullable_float_array_length != b->a_nullable_float_array_length) { + return FALSE; + } + for (size_t i = 0; i < a->a_nullable_float_array_length; i++) { + if (!flpigeon_equals_double(a->a_nullable_float_array[i], + b->a_nullable_float_array[i])) { + return FALSE; + } + } + } + if ((a->a_nullable_enum == nullptr) != (b->a_nullable_enum == nullptr)) { + return FALSE; + } + if (a->a_nullable_enum != nullptr && + *a->a_nullable_enum != *b->a_nullable_enum) { + return FALSE; + } + if ((a->another_nullable_enum == nullptr) != + (b->another_nullable_enum == nullptr)) { + return FALSE; + } + if (a->another_nullable_enum != nullptr && + *a->another_nullable_enum != *b->another_nullable_enum) { + return FALSE; + } + if (g_strcmp0(a->a_nullable_string, b->a_nullable_string) != 0) { + return FALSE; + } + if (!flpigeon_deep_equals(a->a_nullable_object, b->a_nullable_object)) { + return FALSE; + } + if (!core_tests_pigeon_test_all_nullable_types_equals( + a->all_nullable_types, b->all_nullable_types)) { + return FALSE; + } + if (!flpigeon_deep_equals(a->list, b->list)) { + return FALSE; + } + if (!flpigeon_deep_equals(a->string_list, b->string_list)) { + return FALSE; + } + if (!flpigeon_deep_equals(a->int_list, b->int_list)) { + return FALSE; + } + if (!flpigeon_deep_equals(a->double_list, b->double_list)) { + return FALSE; + } + if (!flpigeon_deep_equals(a->bool_list, b->bool_list)) { + return FALSE; + } + if (!flpigeon_deep_equals(a->enum_list, b->enum_list)) { + return FALSE; + } + if (!flpigeon_deep_equals(a->object_list, b->object_list)) { + return FALSE; + } + if (!flpigeon_deep_equals(a->list_list, b->list_list)) { + return FALSE; + } + if (!flpigeon_deep_equals(a->map_list, b->map_list)) { + return FALSE; + } + if (!flpigeon_deep_equals(a->recursive_class_list, b->recursive_class_list)) { + return FALSE; + } + if (!flpigeon_deep_equals(a->map, b->map)) { + return FALSE; + } + if (!flpigeon_deep_equals(a->string_map, b->string_map)) { + return FALSE; + } + if (!flpigeon_deep_equals(a->int_map, b->int_map)) { + return FALSE; + } + if (!flpigeon_deep_equals(a->enum_map, b->enum_map)) { + return FALSE; + } + if (!flpigeon_deep_equals(a->object_map, b->object_map)) { + return FALSE; + } + if (!flpigeon_deep_equals(a->list_map, b->list_map)) { + return FALSE; + } + if (!flpigeon_deep_equals(a->map_map, b->map_map)) { + return FALSE; + } + if (!flpigeon_deep_equals(a->recursive_class_map, b->recursive_class_map)) { + return FALSE; + } + return TRUE; +} + +guint core_tests_pigeon_test_all_nullable_types_hash( + CoreTestsPigeonTestAllNullableTypes* self) { + g_return_val_if_fail(CORE_TESTS_PIGEON_TEST_IS_ALL_NULLABLE_TYPES(self), 0); + guint result = 0; + result = result * 31 + (self->a_nullable_bool != nullptr + ? static_cast(*self->a_nullable_bool) + : 0); + result = result * 31 + (self->a_nullable_int != nullptr + ? static_cast(*self->a_nullable_int) + : 0); + result = result * 31 + (self->a_nullable_int64 != nullptr + ? static_cast(*self->a_nullable_int64) + : 0); + result = result * 31 + (self->a_nullable_double != nullptr + ? flpigeon_hash_double(*self->a_nullable_double) + : 0); + { + size_t len = self->a_nullable_byte_array_length; + const uint8_t* data = self->a_nullable_byte_array; + if (data != nullptr) { + for (size_t i = 0; i < len; i++) { + result = result * 31 + static_cast(data[i]); + } + } + } + { + size_t len = self->a_nullable4_byte_array_length; + const int32_t* data = self->a_nullable4_byte_array; + if (data != nullptr) { + for (size_t i = 0; i < len; i++) { + result = result * 31 + static_cast(data[i]); + } + } + } + { + size_t len = self->a_nullable8_byte_array_length; + const int64_t* data = self->a_nullable8_byte_array; + if (data != nullptr) { + for (size_t i = 0; i < len; i++) { + result = result * 31 + static_cast(data[i] ^ (data[i] >> 32)); + } + } + } + { + size_t len = self->a_nullable_float_array_length; + const double* data = self->a_nullable_float_array; + if (data != nullptr) { + for (size_t i = 0; i < len; i++) { + result = result * 31 + flpigeon_hash_double(data[i]); + } + } + } + result = result * 31 + (self->a_nullable_enum != nullptr + ? static_cast(*self->a_nullable_enum) + : 0); + result = result * 31 + (self->another_nullable_enum != nullptr + ? static_cast(*self->another_nullable_enum) + : 0); + result = result * 31 + (self->a_nullable_string != nullptr + ? g_str_hash(self->a_nullable_string) + : 0); + result = result * 31 + flpigeon_deep_hash(self->a_nullable_object); + result = result * 31 + core_tests_pigeon_test_all_nullable_types_hash( + self->all_nullable_types); + result = result * 31 + flpigeon_deep_hash(self->list); + result = result * 31 + flpigeon_deep_hash(self->string_list); + result = result * 31 + flpigeon_deep_hash(self->int_list); + result = result * 31 + flpigeon_deep_hash(self->double_list); + result = result * 31 + flpigeon_deep_hash(self->bool_list); + result = result * 31 + flpigeon_deep_hash(self->enum_list); + result = result * 31 + flpigeon_deep_hash(self->object_list); + result = result * 31 + flpigeon_deep_hash(self->list_list); + result = result * 31 + flpigeon_deep_hash(self->map_list); + result = result * 31 + flpigeon_deep_hash(self->recursive_class_list); + result = result * 31 + flpigeon_deep_hash(self->map); + result = result * 31 + flpigeon_deep_hash(self->string_map); + result = result * 31 + flpigeon_deep_hash(self->int_map); + result = result * 31 + flpigeon_deep_hash(self->enum_map); + result = result * 31 + flpigeon_deep_hash(self->object_map); + result = result * 31 + flpigeon_deep_hash(self->list_map); + result = result * 31 + flpigeon_deep_hash(self->map_map); + result = result * 31 + flpigeon_deep_hash(self->recursive_class_map); + return result; +} + struct _CoreTestsPigeonTestAllNullableTypesWithoutRecursion { GObject parent_instance; @@ -2145,6 +2815,251 @@ core_tests_pigeon_test_all_nullable_types_without_recursion_new_from_list( list_map, map_map); } +gboolean core_tests_pigeon_test_all_nullable_types_without_recursion_equals( + CoreTestsPigeonTestAllNullableTypesWithoutRecursion* a, + CoreTestsPigeonTestAllNullableTypesWithoutRecursion* b) { + if (a == b) { + return TRUE; + } + if (a == nullptr || b == nullptr) { + return FALSE; + } + if ((a->a_nullable_bool == nullptr) != (b->a_nullable_bool == nullptr)) { + return FALSE; + } + if (a->a_nullable_bool != nullptr && + *a->a_nullable_bool != *b->a_nullable_bool) { + return FALSE; + } + if ((a->a_nullable_int == nullptr) != (b->a_nullable_int == nullptr)) { + return FALSE; + } + if (a->a_nullable_int != nullptr && + *a->a_nullable_int != *b->a_nullable_int) { + return FALSE; + } + if ((a->a_nullable_int64 == nullptr) != (b->a_nullable_int64 == nullptr)) { + return FALSE; + } + if (a->a_nullable_int64 != nullptr && + *a->a_nullable_int64 != *b->a_nullable_int64) { + return FALSE; + } + if ((a->a_nullable_double == nullptr) != (b->a_nullable_double == nullptr)) { + return FALSE; + } + if (a->a_nullable_double != nullptr && + !flpigeon_equals_double(*a->a_nullable_double, *b->a_nullable_double)) { + return FALSE; + } + if (a->a_nullable_byte_array != b->a_nullable_byte_array) { + if (a->a_nullable_byte_array == nullptr || + b->a_nullable_byte_array == nullptr) { + return FALSE; + } + if (a->a_nullable_byte_array_length != b->a_nullable_byte_array_length) { + return FALSE; + } + if (memcmp(a->a_nullable_byte_array, b->a_nullable_byte_array, + a->a_nullable_byte_array_length * sizeof(uint8_t)) != 0) { + return FALSE; + } + } + if (a->a_nullable4_byte_array != b->a_nullable4_byte_array) { + if (a->a_nullable4_byte_array == nullptr || + b->a_nullable4_byte_array == nullptr) { + return FALSE; + } + if (a->a_nullable4_byte_array_length != b->a_nullable4_byte_array_length) { + return FALSE; + } + if (memcmp(a->a_nullable4_byte_array, b->a_nullable4_byte_array, + a->a_nullable4_byte_array_length * sizeof(int32_t)) != 0) { + return FALSE; + } + } + if (a->a_nullable8_byte_array != b->a_nullable8_byte_array) { + if (a->a_nullable8_byte_array == nullptr || + b->a_nullable8_byte_array == nullptr) { + return FALSE; + } + if (a->a_nullable8_byte_array_length != b->a_nullable8_byte_array_length) { + return FALSE; + } + if (memcmp(a->a_nullable8_byte_array, b->a_nullable8_byte_array, + a->a_nullable8_byte_array_length * sizeof(int64_t)) != 0) { + return FALSE; + } + } + if (a->a_nullable_float_array != b->a_nullable_float_array) { + if (a->a_nullable_float_array == nullptr || + b->a_nullable_float_array == nullptr) { + return FALSE; + } + if (a->a_nullable_float_array_length != b->a_nullable_float_array_length) { + return FALSE; + } + for (size_t i = 0; i < a->a_nullable_float_array_length; i++) { + if (!flpigeon_equals_double(a->a_nullable_float_array[i], + b->a_nullable_float_array[i])) { + return FALSE; + } + } + } + if ((a->a_nullable_enum == nullptr) != (b->a_nullable_enum == nullptr)) { + return FALSE; + } + if (a->a_nullable_enum != nullptr && + *a->a_nullable_enum != *b->a_nullable_enum) { + return FALSE; + } + if ((a->another_nullable_enum == nullptr) != + (b->another_nullable_enum == nullptr)) { + return FALSE; + } + if (a->another_nullable_enum != nullptr && + *a->another_nullable_enum != *b->another_nullable_enum) { + return FALSE; + } + if (g_strcmp0(a->a_nullable_string, b->a_nullable_string) != 0) { + return FALSE; + } + if (!flpigeon_deep_equals(a->a_nullable_object, b->a_nullable_object)) { + return FALSE; + } + if (!flpigeon_deep_equals(a->list, b->list)) { + return FALSE; + } + if (!flpigeon_deep_equals(a->string_list, b->string_list)) { + return FALSE; + } + if (!flpigeon_deep_equals(a->int_list, b->int_list)) { + return FALSE; + } + if (!flpigeon_deep_equals(a->double_list, b->double_list)) { + return FALSE; + } + if (!flpigeon_deep_equals(a->bool_list, b->bool_list)) { + return FALSE; + } + if (!flpigeon_deep_equals(a->enum_list, b->enum_list)) { + return FALSE; + } + if (!flpigeon_deep_equals(a->object_list, b->object_list)) { + return FALSE; + } + if (!flpigeon_deep_equals(a->list_list, b->list_list)) { + return FALSE; + } + if (!flpigeon_deep_equals(a->map_list, b->map_list)) { + return FALSE; + } + if (!flpigeon_deep_equals(a->map, b->map)) { + return FALSE; + } + if (!flpigeon_deep_equals(a->string_map, b->string_map)) { + return FALSE; + } + if (!flpigeon_deep_equals(a->int_map, b->int_map)) { + return FALSE; + } + if (!flpigeon_deep_equals(a->enum_map, b->enum_map)) { + return FALSE; + } + if (!flpigeon_deep_equals(a->object_map, b->object_map)) { + return FALSE; + } + if (!flpigeon_deep_equals(a->list_map, b->list_map)) { + return FALSE; + } + if (!flpigeon_deep_equals(a->map_map, b->map_map)) { + return FALSE; + } + return TRUE; +} + +guint core_tests_pigeon_test_all_nullable_types_without_recursion_hash( + CoreTestsPigeonTestAllNullableTypesWithoutRecursion* self) { + g_return_val_if_fail( + CORE_TESTS_PIGEON_TEST_IS_ALL_NULLABLE_TYPES_WITHOUT_RECURSION(self), 0); + guint result = 0; + result = result * 31 + (self->a_nullable_bool != nullptr + ? static_cast(*self->a_nullable_bool) + : 0); + result = result * 31 + (self->a_nullable_int != nullptr + ? static_cast(*self->a_nullable_int) + : 0); + result = result * 31 + (self->a_nullable_int64 != nullptr + ? static_cast(*self->a_nullable_int64) + : 0); + result = result * 31 + (self->a_nullable_double != nullptr + ? flpigeon_hash_double(*self->a_nullable_double) + : 0); + { + size_t len = self->a_nullable_byte_array_length; + const uint8_t* data = self->a_nullable_byte_array; + if (data != nullptr) { + for (size_t i = 0; i < len; i++) { + result = result * 31 + static_cast(data[i]); + } + } + } + { + size_t len = self->a_nullable4_byte_array_length; + const int32_t* data = self->a_nullable4_byte_array; + if (data != nullptr) { + for (size_t i = 0; i < len; i++) { + result = result * 31 + static_cast(data[i]); + } + } + } + { + size_t len = self->a_nullable8_byte_array_length; + const int64_t* data = self->a_nullable8_byte_array; + if (data != nullptr) { + for (size_t i = 0; i < len; i++) { + result = result * 31 + static_cast(data[i] ^ (data[i] >> 32)); + } + } + } + { + size_t len = self->a_nullable_float_array_length; + const double* data = self->a_nullable_float_array; + if (data != nullptr) { + for (size_t i = 0; i < len; i++) { + result = result * 31 + flpigeon_hash_double(data[i]); + } + } + } + result = result * 31 + (self->a_nullable_enum != nullptr + ? static_cast(*self->a_nullable_enum) + : 0); + result = result * 31 + (self->another_nullable_enum != nullptr + ? static_cast(*self->another_nullable_enum) + : 0); + result = result * 31 + (self->a_nullable_string != nullptr + ? g_str_hash(self->a_nullable_string) + : 0); + result = result * 31 + flpigeon_deep_hash(self->a_nullable_object); + result = result * 31 + flpigeon_deep_hash(self->list); + result = result * 31 + flpigeon_deep_hash(self->string_list); + result = result * 31 + flpigeon_deep_hash(self->int_list); + result = result * 31 + flpigeon_deep_hash(self->double_list); + result = result * 31 + flpigeon_deep_hash(self->bool_list); + result = result * 31 + flpigeon_deep_hash(self->enum_list); + result = result * 31 + flpigeon_deep_hash(self->object_list); + result = result * 31 + flpigeon_deep_hash(self->list_list); + result = result * 31 + flpigeon_deep_hash(self->map_list); + result = result * 31 + flpigeon_deep_hash(self->map); + result = result * 31 + flpigeon_deep_hash(self->string_map); + result = result * 31 + flpigeon_deep_hash(self->int_map); + result = result * 31 + flpigeon_deep_hash(self->enum_map); + result = result * 31 + flpigeon_deep_hash(self->object_map); + result = result * 31 + flpigeon_deep_hash(self->list_map); + result = result * 31 + flpigeon_deep_hash(self->map_map); + return result; +} + struct _CoreTestsPigeonTestAllClassesWrapper { GObject parent_instance; @@ -2347,6 +3262,59 @@ core_tests_pigeon_test_all_classes_wrapper_new_from_list(FlValue* values) { class_list, nullable_class_list, class_map, nullable_class_map); } +gboolean core_tests_pigeon_test_all_classes_wrapper_equals( + CoreTestsPigeonTestAllClassesWrapper* a, + CoreTestsPigeonTestAllClassesWrapper* b) { + if (a == b) { + return TRUE; + } + if (a == nullptr || b == nullptr) { + return FALSE; + } + if (!core_tests_pigeon_test_all_nullable_types_equals( + a->all_nullable_types, b->all_nullable_types)) { + return FALSE; + } + if (!core_tests_pigeon_test_all_nullable_types_without_recursion_equals( + a->all_nullable_types_without_recursion, + b->all_nullable_types_without_recursion)) { + return FALSE; + } + if (!core_tests_pigeon_test_all_types_equals(a->all_types, b->all_types)) { + return FALSE; + } + if (!flpigeon_deep_equals(a->class_list, b->class_list)) { + return FALSE; + } + if (!flpigeon_deep_equals(a->nullable_class_list, b->nullable_class_list)) { + return FALSE; + } + if (!flpigeon_deep_equals(a->class_map, b->class_map)) { + return FALSE; + } + if (!flpigeon_deep_equals(a->nullable_class_map, b->nullable_class_map)) { + return FALSE; + } + return TRUE; +} + +guint core_tests_pigeon_test_all_classes_wrapper_hash( + CoreTestsPigeonTestAllClassesWrapper* self) { + g_return_val_if_fail(CORE_TESTS_PIGEON_TEST_IS_ALL_CLASSES_WRAPPER(self), 0); + guint result = 0; + result = result * 31 + core_tests_pigeon_test_all_nullable_types_hash( + self->all_nullable_types); + result = result * 31 + + core_tests_pigeon_test_all_nullable_types_without_recursion_hash( + self->all_nullable_types_without_recursion); + result = result * 31 + core_tests_pigeon_test_all_types_hash(self->all_types); + result = result * 31 + flpigeon_deep_hash(self->class_list); + result = result * 31 + flpigeon_deep_hash(self->nullable_class_list); + result = result * 31 + flpigeon_deep_hash(self->class_map); + result = result * 31 + flpigeon_deep_hash(self->nullable_class_map); + return result; +} + struct _CoreTestsPigeonTestTestMessage { GObject parent_instance; @@ -2409,6 +3377,28 @@ core_tests_pigeon_test_test_message_new_from_list(FlValue* values) { return core_tests_pigeon_test_test_message_new(test_list); } +gboolean core_tests_pigeon_test_test_message_equals( + CoreTestsPigeonTestTestMessage* a, CoreTestsPigeonTestTestMessage* b) { + if (a == b) { + return TRUE; + } + if (a == nullptr || b == nullptr) { + return FALSE; + } + if (!flpigeon_deep_equals(a->test_list, b->test_list)) { + return FALSE; + } + return TRUE; +} + +guint core_tests_pigeon_test_test_message_hash( + CoreTestsPigeonTestTestMessage* self) { + g_return_val_if_fail(CORE_TESTS_PIGEON_TEST_IS_TEST_MESSAGE(self), 0); + guint result = 0; + result = result * 31 + flpigeon_deep_hash(self->test_list); + return result; +} + struct _CoreTestsPigeonTestMessageCodec { FlStandardMessageCodec parent_instance; }; @@ -4840,6 +5830,208 @@ core_tests_pigeon_test_host_integration_core_api_echo_required_int_response_new_ return self; } +struct + _CoreTestsPigeonTestHostIntegrationCoreApiAreAllNullableTypesEqualResponse { + GObject parent_instance; + + FlValue* value; +}; + +G_DEFINE_TYPE( + CoreTestsPigeonTestHostIntegrationCoreApiAreAllNullableTypesEqualResponse, + core_tests_pigeon_test_host_integration_core_api_are_all_nullable_types_equal_response, + G_TYPE_OBJECT) + +static void +core_tests_pigeon_test_host_integration_core_api_are_all_nullable_types_equal_response_dispose( + GObject* object) { + CoreTestsPigeonTestHostIntegrationCoreApiAreAllNullableTypesEqualResponse* self = + CORE_TESTS_PIGEON_TEST_HOST_INTEGRATION_CORE_API_ARE_ALL_NULLABLE_TYPES_EQUAL_RESPONSE( + object); + g_clear_pointer(&self->value, fl_value_unref); + G_OBJECT_CLASS( + core_tests_pigeon_test_host_integration_core_api_are_all_nullable_types_equal_response_parent_class) + ->dispose(object); +} + +static void +core_tests_pigeon_test_host_integration_core_api_are_all_nullable_types_equal_response_init( + CoreTestsPigeonTestHostIntegrationCoreApiAreAllNullableTypesEqualResponse* + self) {} + +static void +core_tests_pigeon_test_host_integration_core_api_are_all_nullable_types_equal_response_class_init( + CoreTestsPigeonTestHostIntegrationCoreApiAreAllNullableTypesEqualResponseClass* + klass) { + G_OBJECT_CLASS(klass)->dispose = + core_tests_pigeon_test_host_integration_core_api_are_all_nullable_types_equal_response_dispose; +} + +CoreTestsPigeonTestHostIntegrationCoreApiAreAllNullableTypesEqualResponse* +core_tests_pigeon_test_host_integration_core_api_are_all_nullable_types_equal_response_new( + gboolean return_value) { + CoreTestsPigeonTestHostIntegrationCoreApiAreAllNullableTypesEqualResponse* self = + CORE_TESTS_PIGEON_TEST_HOST_INTEGRATION_CORE_API_ARE_ALL_NULLABLE_TYPES_EQUAL_RESPONSE( + g_object_new( + core_tests_pigeon_test_host_integration_core_api_are_all_nullable_types_equal_response_get_type(), + nullptr)); + self->value = fl_value_new_list(); + fl_value_append_take(self->value, fl_value_new_bool(return_value)); + return self; +} + +CoreTestsPigeonTestHostIntegrationCoreApiAreAllNullableTypesEqualResponse* +core_tests_pigeon_test_host_integration_core_api_are_all_nullable_types_equal_response_new_error( + const gchar* code, const gchar* message, FlValue* details) { + CoreTestsPigeonTestHostIntegrationCoreApiAreAllNullableTypesEqualResponse* self = + CORE_TESTS_PIGEON_TEST_HOST_INTEGRATION_CORE_API_ARE_ALL_NULLABLE_TYPES_EQUAL_RESPONSE( + g_object_new( + core_tests_pigeon_test_host_integration_core_api_are_all_nullable_types_equal_response_get_type(), + nullptr)); + self->value = fl_value_new_list(); + fl_value_append_take(self->value, fl_value_new_string(code)); + fl_value_append_take(self->value, + fl_value_new_string(message != nullptr ? message : "")); + fl_value_append_take(self->value, details != nullptr ? fl_value_ref(details) + : fl_value_new_null()); + return self; +} + +struct + _CoreTestsPigeonTestHostIntegrationCoreApiGetAllNullableTypesHashResponse { + GObject parent_instance; + + FlValue* value; +}; + +G_DEFINE_TYPE( + CoreTestsPigeonTestHostIntegrationCoreApiGetAllNullableTypesHashResponse, + core_tests_pigeon_test_host_integration_core_api_get_all_nullable_types_hash_response, + G_TYPE_OBJECT) + +static void +core_tests_pigeon_test_host_integration_core_api_get_all_nullable_types_hash_response_dispose( + GObject* object) { + CoreTestsPigeonTestHostIntegrationCoreApiGetAllNullableTypesHashResponse* self = + CORE_TESTS_PIGEON_TEST_HOST_INTEGRATION_CORE_API_GET_ALL_NULLABLE_TYPES_HASH_RESPONSE( + object); + g_clear_pointer(&self->value, fl_value_unref); + G_OBJECT_CLASS( + core_tests_pigeon_test_host_integration_core_api_get_all_nullable_types_hash_response_parent_class) + ->dispose(object); +} + +static void +core_tests_pigeon_test_host_integration_core_api_get_all_nullable_types_hash_response_init( + CoreTestsPigeonTestHostIntegrationCoreApiGetAllNullableTypesHashResponse* + self) {} + +static void +core_tests_pigeon_test_host_integration_core_api_get_all_nullable_types_hash_response_class_init( + CoreTestsPigeonTestHostIntegrationCoreApiGetAllNullableTypesHashResponseClass* + klass) { + G_OBJECT_CLASS(klass)->dispose = + core_tests_pigeon_test_host_integration_core_api_get_all_nullable_types_hash_response_dispose; +} + +CoreTestsPigeonTestHostIntegrationCoreApiGetAllNullableTypesHashResponse* +core_tests_pigeon_test_host_integration_core_api_get_all_nullable_types_hash_response_new( + int64_t return_value) { + CoreTestsPigeonTestHostIntegrationCoreApiGetAllNullableTypesHashResponse* self = + CORE_TESTS_PIGEON_TEST_HOST_INTEGRATION_CORE_API_GET_ALL_NULLABLE_TYPES_HASH_RESPONSE( + g_object_new( + core_tests_pigeon_test_host_integration_core_api_get_all_nullable_types_hash_response_get_type(), + nullptr)); + self->value = fl_value_new_list(); + fl_value_append_take(self->value, fl_value_new_int(return_value)); + return self; +} + +CoreTestsPigeonTestHostIntegrationCoreApiGetAllNullableTypesHashResponse* +core_tests_pigeon_test_host_integration_core_api_get_all_nullable_types_hash_response_new_error( + const gchar* code, const gchar* message, FlValue* details) { + CoreTestsPigeonTestHostIntegrationCoreApiGetAllNullableTypesHashResponse* self = + CORE_TESTS_PIGEON_TEST_HOST_INTEGRATION_CORE_API_GET_ALL_NULLABLE_TYPES_HASH_RESPONSE( + g_object_new( + core_tests_pigeon_test_host_integration_core_api_get_all_nullable_types_hash_response_get_type(), + nullptr)); + self->value = fl_value_new_list(); + fl_value_append_take(self->value, fl_value_new_string(code)); + fl_value_append_take(self->value, + fl_value_new_string(message != nullptr ? message : "")); + fl_value_append_take(self->value, details != nullptr ? fl_value_ref(details) + : fl_value_new_null()); + return self; +} + +struct + _CoreTestsPigeonTestHostIntegrationCoreApiGetAllNullableTypesWithoutRecursionHashResponse { + GObject parent_instance; + + FlValue* value; +}; + +G_DEFINE_TYPE( + CoreTestsPigeonTestHostIntegrationCoreApiGetAllNullableTypesWithoutRecursionHashResponse, + core_tests_pigeon_test_host_integration_core_api_get_all_nullable_types_without_recursion_hash_response, + G_TYPE_OBJECT) + +static void +core_tests_pigeon_test_host_integration_core_api_get_all_nullable_types_without_recursion_hash_response_dispose( + GObject* object) { + CoreTestsPigeonTestHostIntegrationCoreApiGetAllNullableTypesWithoutRecursionHashResponse* + self = + CORE_TESTS_PIGEON_TEST_HOST_INTEGRATION_CORE_API_GET_ALL_NULLABLE_TYPES_WITHOUT_RECURSION_HASH_RESPONSE( + object); + g_clear_pointer(&self->value, fl_value_unref); + G_OBJECT_CLASS( + core_tests_pigeon_test_host_integration_core_api_get_all_nullable_types_without_recursion_hash_response_parent_class) + ->dispose(object); +} + +static void +core_tests_pigeon_test_host_integration_core_api_get_all_nullable_types_without_recursion_hash_response_init( + CoreTestsPigeonTestHostIntegrationCoreApiGetAllNullableTypesWithoutRecursionHashResponse* + self) {} + +static void +core_tests_pigeon_test_host_integration_core_api_get_all_nullable_types_without_recursion_hash_response_class_init( + CoreTestsPigeonTestHostIntegrationCoreApiGetAllNullableTypesWithoutRecursionHashResponseClass* + klass) { + G_OBJECT_CLASS(klass)->dispose = + core_tests_pigeon_test_host_integration_core_api_get_all_nullable_types_without_recursion_hash_response_dispose; +} + +CoreTestsPigeonTestHostIntegrationCoreApiGetAllNullableTypesWithoutRecursionHashResponse* +core_tests_pigeon_test_host_integration_core_api_get_all_nullable_types_without_recursion_hash_response_new( + int64_t return_value) { + CoreTestsPigeonTestHostIntegrationCoreApiGetAllNullableTypesWithoutRecursionHashResponse* + self = CORE_TESTS_PIGEON_TEST_HOST_INTEGRATION_CORE_API_GET_ALL_NULLABLE_TYPES_WITHOUT_RECURSION_HASH_RESPONSE( + g_object_new( + core_tests_pigeon_test_host_integration_core_api_get_all_nullable_types_without_recursion_hash_response_get_type(), + nullptr)); + self->value = fl_value_new_list(); + fl_value_append_take(self->value, fl_value_new_int(return_value)); + return self; +} + +CoreTestsPigeonTestHostIntegrationCoreApiGetAllNullableTypesWithoutRecursionHashResponse* +core_tests_pigeon_test_host_integration_core_api_get_all_nullable_types_without_recursion_hash_response_new_error( + const gchar* code, const gchar* message, FlValue* details) { + CoreTestsPigeonTestHostIntegrationCoreApiGetAllNullableTypesWithoutRecursionHashResponse* + self = CORE_TESTS_PIGEON_TEST_HOST_INTEGRATION_CORE_API_GET_ALL_NULLABLE_TYPES_WITHOUT_RECURSION_HASH_RESPONSE( + g_object_new( + core_tests_pigeon_test_host_integration_core_api_get_all_nullable_types_without_recursion_hash_response_get_type(), + nullptr)); + self->value = fl_value_new_list(); + fl_value_append_take(self->value, fl_value_new_string(code)); + fl_value_append_take(self->value, + fl_value_new_string(message != nullptr ? message : "")); + fl_value_append_take(self->value, details != nullptr ? fl_value_ref(details) + : fl_value_new_null()); + return self; +} + struct _CoreTestsPigeonTestHostIntegrationCoreApiEchoAllNullableTypesResponse { GObject parent_instance; @@ -14726,6 +15918,112 @@ core_tests_pigeon_test_host_integration_core_api_echo_required_int_cb( } } +static void +core_tests_pigeon_test_host_integration_core_api_are_all_nullable_types_equal_cb( + FlBasicMessageChannel* channel, FlValue* message_, + FlBasicMessageChannelResponseHandle* response_handle, gpointer user_data) { + CoreTestsPigeonTestHostIntegrationCoreApi* self = + CORE_TESTS_PIGEON_TEST_HOST_INTEGRATION_CORE_API(user_data); + + if (self->vtable == nullptr || + self->vtable->are_all_nullable_types_equal == nullptr) { + return; + } + + FlValue* value0 = fl_value_get_list_value(message_, 0); + CoreTestsPigeonTestAllNullableTypes* a = + CORE_TESTS_PIGEON_TEST_ALL_NULLABLE_TYPES( + fl_value_get_custom_value_object(value0)); + FlValue* value1 = fl_value_get_list_value(message_, 1); + CoreTestsPigeonTestAllNullableTypes* b = + CORE_TESTS_PIGEON_TEST_ALL_NULLABLE_TYPES( + fl_value_get_custom_value_object(value1)); + g_autoptr( + CoreTestsPigeonTestHostIntegrationCoreApiAreAllNullableTypesEqualResponse) + response = + self->vtable->are_all_nullable_types_equal(a, b, self->user_data); + if (response == nullptr) { + g_warning("No response returned to %s.%s", "HostIntegrationCoreApi", + "areAllNullableTypesEqual"); + return; + } + + g_autoptr(GError) error = NULL; + if (!fl_basic_message_channel_respond(channel, response_handle, + response->value, &error)) { + g_warning("Failed to send response to %s.%s: %s", "HostIntegrationCoreApi", + "areAllNullableTypesEqual", error->message); + } +} + +static void +core_tests_pigeon_test_host_integration_core_api_get_all_nullable_types_hash_cb( + FlBasicMessageChannel* channel, FlValue* message_, + FlBasicMessageChannelResponseHandle* response_handle, gpointer user_data) { + CoreTestsPigeonTestHostIntegrationCoreApi* self = + CORE_TESTS_PIGEON_TEST_HOST_INTEGRATION_CORE_API(user_data); + + if (self->vtable == nullptr || + self->vtable->get_all_nullable_types_hash == nullptr) { + return; + } + + FlValue* value0 = fl_value_get_list_value(message_, 0); + CoreTestsPigeonTestAllNullableTypes* value = + CORE_TESTS_PIGEON_TEST_ALL_NULLABLE_TYPES( + fl_value_get_custom_value_object(value0)); + g_autoptr( + CoreTestsPigeonTestHostIntegrationCoreApiGetAllNullableTypesHashResponse) + response = + self->vtable->get_all_nullable_types_hash(value, self->user_data); + if (response == nullptr) { + g_warning("No response returned to %s.%s", "HostIntegrationCoreApi", + "getAllNullableTypesHash"); + return; + } + + g_autoptr(GError) error = NULL; + if (!fl_basic_message_channel_respond(channel, response_handle, + response->value, &error)) { + g_warning("Failed to send response to %s.%s: %s", "HostIntegrationCoreApi", + "getAllNullableTypesHash", error->message); + } +} + +static void +core_tests_pigeon_test_host_integration_core_api_get_all_nullable_types_without_recursion_hash_cb( + FlBasicMessageChannel* channel, FlValue* message_, + FlBasicMessageChannelResponseHandle* response_handle, gpointer user_data) { + CoreTestsPigeonTestHostIntegrationCoreApi* self = + CORE_TESTS_PIGEON_TEST_HOST_INTEGRATION_CORE_API(user_data); + + if (self->vtable == nullptr || + self->vtable->get_all_nullable_types_without_recursion_hash == nullptr) { + return; + } + + FlValue* value0 = fl_value_get_list_value(message_, 0); + CoreTestsPigeonTestAllNullableTypesWithoutRecursion* value = + CORE_TESTS_PIGEON_TEST_ALL_NULLABLE_TYPES_WITHOUT_RECURSION( + fl_value_get_custom_value_object(value0)); + g_autoptr( + CoreTestsPigeonTestHostIntegrationCoreApiGetAllNullableTypesWithoutRecursionHashResponse) + response = self->vtable->get_all_nullable_types_without_recursion_hash( + value, self->user_data); + if (response == nullptr) { + g_warning("No response returned to %s.%s", "HostIntegrationCoreApi", + "getAllNullableTypesWithoutRecursionHash"); + return; + } + + g_autoptr(GError) error = NULL; + if (!fl_basic_message_channel_respond(channel, response_handle, + response->value, &error)) { + g_warning("Failed to send response to %s.%s: %s", "HostIntegrationCoreApi", + "getAllNullableTypesWithoutRecursionHash", error->message); + } +} + static void core_tests_pigeon_test_host_integration_core_api_echo_all_nullable_types_cb( FlBasicMessageChannel* channel, FlValue* message_, @@ -18082,6 +19380,45 @@ void core_tests_pigeon_test_host_integration_core_api_set_method_handlers( echo_required_int_channel, core_tests_pigeon_test_host_integration_core_api_echo_required_int_cb, g_object_ref(api_data), g_object_unref); + g_autofree gchar* are_all_nullable_types_equal_channel_name = g_strdup_printf( + "dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi." + "areAllNullableTypesEqual%s", + dot_suffix); + g_autoptr(FlBasicMessageChannel) are_all_nullable_types_equal_channel = + fl_basic_message_channel_new(messenger, + are_all_nullable_types_equal_channel_name, + FL_MESSAGE_CODEC(codec)); + fl_basic_message_channel_set_message_handler( + are_all_nullable_types_equal_channel, + core_tests_pigeon_test_host_integration_core_api_are_all_nullable_types_equal_cb, + g_object_ref(api_data), g_object_unref); + g_autofree gchar* get_all_nullable_types_hash_channel_name = g_strdup_printf( + "dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi." + "getAllNullableTypesHash%s", + dot_suffix); + g_autoptr(FlBasicMessageChannel) get_all_nullable_types_hash_channel = + fl_basic_message_channel_new(messenger, + get_all_nullable_types_hash_channel_name, + FL_MESSAGE_CODEC(codec)); + fl_basic_message_channel_set_message_handler( + get_all_nullable_types_hash_channel, + core_tests_pigeon_test_host_integration_core_api_get_all_nullable_types_hash_cb, + g_object_ref(api_data), g_object_unref); + g_autofree gchar* get_all_nullable_types_without_recursion_hash_channel_name = + g_strdup_printf( + "dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi." + "getAllNullableTypesWithoutRecursionHash%s", + dot_suffix); + g_autoptr(FlBasicMessageChannel) + get_all_nullable_types_without_recursion_hash_channel = + fl_basic_message_channel_new( + messenger, + get_all_nullable_types_without_recursion_hash_channel_name, + FL_MESSAGE_CODEC(codec)); + fl_basic_message_channel_set_message_handler( + get_all_nullable_types_without_recursion_hash_channel, + core_tests_pigeon_test_host_integration_core_api_get_all_nullable_types_without_recursion_hash_cb, + g_object_ref(api_data), g_object_unref); g_autofree gchar* echo_all_nullable_types_channel_name = g_strdup_printf( "dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi." "echoAllNullableTypes%s", @@ -19917,6 +21254,40 @@ void core_tests_pigeon_test_host_integration_core_api_clear_method_handlers( FL_MESSAGE_CODEC(codec)); fl_basic_message_channel_set_message_handler(echo_required_int_channel, nullptr, nullptr, nullptr); + g_autofree gchar* are_all_nullable_types_equal_channel_name = g_strdup_printf( + "dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi." + "areAllNullableTypesEqual%s", + dot_suffix); + g_autoptr(FlBasicMessageChannel) are_all_nullable_types_equal_channel = + fl_basic_message_channel_new(messenger, + are_all_nullable_types_equal_channel_name, + FL_MESSAGE_CODEC(codec)); + fl_basic_message_channel_set_message_handler( + are_all_nullable_types_equal_channel, nullptr, nullptr, nullptr); + g_autofree gchar* get_all_nullable_types_hash_channel_name = g_strdup_printf( + "dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi." + "getAllNullableTypesHash%s", + dot_suffix); + g_autoptr(FlBasicMessageChannel) get_all_nullable_types_hash_channel = + fl_basic_message_channel_new(messenger, + get_all_nullable_types_hash_channel_name, + FL_MESSAGE_CODEC(codec)); + fl_basic_message_channel_set_message_handler( + get_all_nullable_types_hash_channel, nullptr, nullptr, nullptr); + g_autofree gchar* get_all_nullable_types_without_recursion_hash_channel_name = + g_strdup_printf( + "dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi." + "getAllNullableTypesWithoutRecursionHash%s", + dot_suffix); + g_autoptr(FlBasicMessageChannel) + get_all_nullable_types_without_recursion_hash_channel = + fl_basic_message_channel_new( + messenger, + get_all_nullable_types_without_recursion_hash_channel_name, + FL_MESSAGE_CODEC(codec)); + fl_basic_message_channel_set_message_handler( + get_all_nullable_types_without_recursion_hash_channel, nullptr, nullptr, + nullptr); g_autofree gchar* echo_all_nullable_types_channel_name = g_strdup_printf( "dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi." "echoAllNullableTypes%s", diff --git a/packages/pigeon/platform_tests/test_plugin/linux/pigeon/core_tests.gen.h b/packages/pigeon/platform_tests/test_plugin/linux/pigeon/core_tests.gen.h index f0f342e75439..322b9bc8a6b5 100644 --- a/packages/pigeon/platform_tests/test_plugin/linux/pigeon/core_tests.gen.h +++ b/packages/pigeon/platform_tests/test_plugin/linux/pigeon/core_tests.gen.h @@ -69,6 +69,29 @@ CoreTestsPigeonTestUnusedClass* core_tests_pigeon_test_unused_class_new( FlValue* core_tests_pigeon_test_unused_class_get_a_field( CoreTestsPigeonTestUnusedClass* object); +/** + * core_tests_pigeon_test_unused_class_equals: + * @a: a #CoreTestsPigeonTestUnusedClass. + * @b: another #CoreTestsPigeonTestUnusedClass. + * + * Checks if two #CoreTestsPigeonTestUnusedClass objects are equal. + * + * Returns: TRUE if @a and @b are equal. + */ +gboolean core_tests_pigeon_test_unused_class_equals( + CoreTestsPigeonTestUnusedClass* a, CoreTestsPigeonTestUnusedClass* b); + +/** + * core_tests_pigeon_test_unused_class_hash: + * @object: a #CoreTestsPigeonTestUnusedClass. + * + * Calculates a hash code for a #CoreTestsPigeonTestUnusedClass object. + * + * Returns: the hash code. + */ +guint core_tests_pigeon_test_unused_class_hash( + CoreTestsPigeonTestUnusedClass* object); + /** * CoreTestsPigeonTestAllTypes: * @@ -445,6 +468,29 @@ FlValue* core_tests_pigeon_test_all_types_get_list_map( FlValue* core_tests_pigeon_test_all_types_get_map_map( CoreTestsPigeonTestAllTypes* object); +/** + * core_tests_pigeon_test_all_types_equals: + * @a: a #CoreTestsPigeonTestAllTypes. + * @b: another #CoreTestsPigeonTestAllTypes. + * + * Checks if two #CoreTestsPigeonTestAllTypes objects are equal. + * + * Returns: TRUE if @a and @b are equal. + */ +gboolean core_tests_pigeon_test_all_types_equals( + CoreTestsPigeonTestAllTypes* a, CoreTestsPigeonTestAllTypes* b); + +/** + * core_tests_pigeon_test_all_types_hash: + * @object: a #CoreTestsPigeonTestAllTypes. + * + * Calculates a hash code for a #CoreTestsPigeonTestAllTypes object. + * + * Returns: the hash code. + */ +guint core_tests_pigeon_test_all_types_hash( + CoreTestsPigeonTestAllTypes* object); + /** * CoreTestsPigeonTestAllNullableTypes: * @@ -868,6 +914,30 @@ FlValue* core_tests_pigeon_test_all_nullable_types_get_map_map( FlValue* core_tests_pigeon_test_all_nullable_types_get_recursive_class_map( CoreTestsPigeonTestAllNullableTypes* object); +/** + * core_tests_pigeon_test_all_nullable_types_equals: + * @a: a #CoreTestsPigeonTestAllNullableTypes. + * @b: another #CoreTestsPigeonTestAllNullableTypes. + * + * Checks if two #CoreTestsPigeonTestAllNullableTypes objects are equal. + * + * Returns: TRUE if @a and @b are equal. + */ +gboolean core_tests_pigeon_test_all_nullable_types_equals( + CoreTestsPigeonTestAllNullableTypes* a, + CoreTestsPigeonTestAllNullableTypes* b); + +/** + * core_tests_pigeon_test_all_nullable_types_hash: + * @object: a #CoreTestsPigeonTestAllNullableTypes. + * + * Calculates a hash code for a #CoreTestsPigeonTestAllNullableTypes object. + * + * Returns: the hash code. + */ +guint core_tests_pigeon_test_all_nullable_types_hash( + CoreTestsPigeonTestAllNullableTypes* object); + /** * CoreTestsPigeonTestAllNullableTypesWithoutRecursion: * @@ -1279,6 +1349,32 @@ FlValue* core_tests_pigeon_test_all_nullable_types_without_recursion_get_map_map( CoreTestsPigeonTestAllNullableTypesWithoutRecursion* object); +/** + * core_tests_pigeon_test_all_nullable_types_without_recursion_equals: + * @a: a #CoreTestsPigeonTestAllNullableTypesWithoutRecursion. + * @b: another #CoreTestsPigeonTestAllNullableTypesWithoutRecursion. + * + * Checks if two #CoreTestsPigeonTestAllNullableTypesWithoutRecursion objects + * are equal. + * + * Returns: TRUE if @a and @b are equal. + */ +gboolean core_tests_pigeon_test_all_nullable_types_without_recursion_equals( + CoreTestsPigeonTestAllNullableTypesWithoutRecursion* a, + CoreTestsPigeonTestAllNullableTypesWithoutRecursion* b); + +/** + * core_tests_pigeon_test_all_nullable_types_without_recursion_hash: + * @object: a #CoreTestsPigeonTestAllNullableTypesWithoutRecursion. + * + * Calculates a hash code for a + * #CoreTestsPigeonTestAllNullableTypesWithoutRecursion object. + * + * Returns: the hash code. + */ +guint core_tests_pigeon_test_all_nullable_types_without_recursion_hash( + CoreTestsPigeonTestAllNullableTypesWithoutRecursion* object); + /** * CoreTestsPigeonTestAllClassesWrapper: * @@ -1396,6 +1492,30 @@ FlValue* core_tests_pigeon_test_all_classes_wrapper_get_class_map( FlValue* core_tests_pigeon_test_all_classes_wrapper_get_nullable_class_map( CoreTestsPigeonTestAllClassesWrapper* object); +/** + * core_tests_pigeon_test_all_classes_wrapper_equals: + * @a: a #CoreTestsPigeonTestAllClassesWrapper. + * @b: another #CoreTestsPigeonTestAllClassesWrapper. + * + * Checks if two #CoreTestsPigeonTestAllClassesWrapper objects are equal. + * + * Returns: TRUE if @a and @b are equal. + */ +gboolean core_tests_pigeon_test_all_classes_wrapper_equals( + CoreTestsPigeonTestAllClassesWrapper* a, + CoreTestsPigeonTestAllClassesWrapper* b); + +/** + * core_tests_pigeon_test_all_classes_wrapper_hash: + * @object: a #CoreTestsPigeonTestAllClassesWrapper. + * + * Calculates a hash code for a #CoreTestsPigeonTestAllClassesWrapper object. + * + * Returns: the hash code. + */ +guint core_tests_pigeon_test_all_classes_wrapper_hash( + CoreTestsPigeonTestAllClassesWrapper* object); + /** * CoreTestsPigeonTestTestMessage: * @@ -1428,6 +1548,29 @@ CoreTestsPigeonTestTestMessage* core_tests_pigeon_test_test_message_new( FlValue* core_tests_pigeon_test_test_message_get_test_list( CoreTestsPigeonTestTestMessage* object); +/** + * core_tests_pigeon_test_test_message_equals: + * @a: a #CoreTestsPigeonTestTestMessage. + * @b: another #CoreTestsPigeonTestTestMessage. + * + * Checks if two #CoreTestsPigeonTestTestMessage objects are equal. + * + * Returns: TRUE if @a and @b are equal. + */ +gboolean core_tests_pigeon_test_test_message_equals( + CoreTestsPigeonTestTestMessage* a, CoreTestsPigeonTestTestMessage* b); + +/** + * core_tests_pigeon_test_test_message_hash: + * @object: a #CoreTestsPigeonTestTestMessage. + * + * Calculates a hash code for a #CoreTestsPigeonTestTestMessage object. + * + * Returns: the hash code. + */ +guint core_tests_pigeon_test_test_message_hash( + CoreTestsPigeonTestTestMessage* object); + G_DECLARE_FINAL_TYPE(CoreTestsPigeonTestMessageCodec, core_tests_pigeon_test_message_codec, CORE_TESTS_PIGEON_TEST, MESSAGE_CODEC, @@ -2451,6 +2594,110 @@ CoreTestsPigeonTestHostIntegrationCoreApiEchoRequiredIntResponse* core_tests_pigeon_test_host_integration_core_api_echo_required_int_response_new_error( const gchar* code, const gchar* message, FlValue* details); +G_DECLARE_FINAL_TYPE( + CoreTestsPigeonTestHostIntegrationCoreApiAreAllNullableTypesEqualResponse, + core_tests_pigeon_test_host_integration_core_api_are_all_nullable_types_equal_response, + CORE_TESTS_PIGEON_TEST, + HOST_INTEGRATION_CORE_API_ARE_ALL_NULLABLE_TYPES_EQUAL_RESPONSE, GObject) + +/** + * core_tests_pigeon_test_host_integration_core_api_are_all_nullable_types_equal_response_new: + * + * Creates a new response to HostIntegrationCoreApi.areAllNullableTypesEqual. + * + * Returns: a new + * #CoreTestsPigeonTestHostIntegrationCoreApiAreAllNullableTypesEqualResponse + */ +CoreTestsPigeonTestHostIntegrationCoreApiAreAllNullableTypesEqualResponse* +core_tests_pigeon_test_host_integration_core_api_are_all_nullable_types_equal_response_new( + gboolean return_value); + +/** + * core_tests_pigeon_test_host_integration_core_api_are_all_nullable_types_equal_response_new_error: + * @code: error code. + * @message: error message. + * @details: (allow-none): error details or %NULL. + * + * Creates a new error response to + * HostIntegrationCoreApi.areAllNullableTypesEqual. + * + * Returns: a new + * #CoreTestsPigeonTestHostIntegrationCoreApiAreAllNullableTypesEqualResponse + */ +CoreTestsPigeonTestHostIntegrationCoreApiAreAllNullableTypesEqualResponse* +core_tests_pigeon_test_host_integration_core_api_are_all_nullable_types_equal_response_new_error( + const gchar* code, const gchar* message, FlValue* details); + +G_DECLARE_FINAL_TYPE( + CoreTestsPigeonTestHostIntegrationCoreApiGetAllNullableTypesHashResponse, + core_tests_pigeon_test_host_integration_core_api_get_all_nullable_types_hash_response, + CORE_TESTS_PIGEON_TEST, + HOST_INTEGRATION_CORE_API_GET_ALL_NULLABLE_TYPES_HASH_RESPONSE, GObject) + +/** + * core_tests_pigeon_test_host_integration_core_api_get_all_nullable_types_hash_response_new: + * + * Creates a new response to HostIntegrationCoreApi.getAllNullableTypesHash. + * + * Returns: a new + * #CoreTestsPigeonTestHostIntegrationCoreApiGetAllNullableTypesHashResponse + */ +CoreTestsPigeonTestHostIntegrationCoreApiGetAllNullableTypesHashResponse* +core_tests_pigeon_test_host_integration_core_api_get_all_nullable_types_hash_response_new( + int64_t return_value); + +/** + * core_tests_pigeon_test_host_integration_core_api_get_all_nullable_types_hash_response_new_error: + * @code: error code. + * @message: error message. + * @details: (allow-none): error details or %NULL. + * + * Creates a new error response to + * HostIntegrationCoreApi.getAllNullableTypesHash. + * + * Returns: a new + * #CoreTestsPigeonTestHostIntegrationCoreApiGetAllNullableTypesHashResponse + */ +CoreTestsPigeonTestHostIntegrationCoreApiGetAllNullableTypesHashResponse* +core_tests_pigeon_test_host_integration_core_api_get_all_nullable_types_hash_response_new_error( + const gchar* code, const gchar* message, FlValue* details); + +G_DECLARE_FINAL_TYPE( + CoreTestsPigeonTestHostIntegrationCoreApiGetAllNullableTypesWithoutRecursionHashResponse, + core_tests_pigeon_test_host_integration_core_api_get_all_nullable_types_without_recursion_hash_response, + CORE_TESTS_PIGEON_TEST, + HOST_INTEGRATION_CORE_API_GET_ALL_NULLABLE_TYPES_WITHOUT_RECURSION_HASH_RESPONSE, + GObject) + +/** + * core_tests_pigeon_test_host_integration_core_api_get_all_nullable_types_without_recursion_hash_response_new: + * + * Creates a new response to + * HostIntegrationCoreApi.getAllNullableTypesWithoutRecursionHash. + * + * Returns: a new + * #CoreTestsPigeonTestHostIntegrationCoreApiGetAllNullableTypesWithoutRecursionHashResponse + */ +CoreTestsPigeonTestHostIntegrationCoreApiGetAllNullableTypesWithoutRecursionHashResponse* +core_tests_pigeon_test_host_integration_core_api_get_all_nullable_types_without_recursion_hash_response_new( + int64_t return_value); + +/** + * core_tests_pigeon_test_host_integration_core_api_get_all_nullable_types_without_recursion_hash_response_new_error: + * @code: error code. + * @message: error message. + * @details: (allow-none): error details or %NULL. + * + * Creates a new error response to + * HostIntegrationCoreApi.getAllNullableTypesWithoutRecursionHash. + * + * Returns: a new + * #CoreTestsPigeonTestHostIntegrationCoreApiGetAllNullableTypesWithoutRecursionHashResponse + */ +CoreTestsPigeonTestHostIntegrationCoreApiGetAllNullableTypesWithoutRecursionHashResponse* +core_tests_pigeon_test_host_integration_core_api_get_all_nullable_types_without_recursion_hash_response_new_error( + const gchar* code, const gchar* message, FlValue* details); + G_DECLARE_FINAL_TYPE( CoreTestsPigeonTestHostIntegrationCoreApiEchoAllNullableTypesResponse, core_tests_pigeon_test_host_integration_core_api_echo_all_nullable_types_response, @@ -3605,6 +3852,17 @@ typedef struct { *echo_optional_default_double)(double a_double, gpointer user_data); CoreTestsPigeonTestHostIntegrationCoreApiEchoRequiredIntResponse* ( *echo_required_int)(int64_t an_int, gpointer user_data); + CoreTestsPigeonTestHostIntegrationCoreApiAreAllNullableTypesEqualResponse* ( + *are_all_nullable_types_equal)(CoreTestsPigeonTestAllNullableTypes* a, + CoreTestsPigeonTestAllNullableTypes* b, + gpointer user_data); + CoreTestsPigeonTestHostIntegrationCoreApiGetAllNullableTypesHashResponse* ( + *get_all_nullable_types_hash)(CoreTestsPigeonTestAllNullableTypes* value, + gpointer user_data); + CoreTestsPigeonTestHostIntegrationCoreApiGetAllNullableTypesWithoutRecursionHashResponse* ( + *get_all_nullable_types_without_recursion_hash)( + CoreTestsPigeonTestAllNullableTypesWithoutRecursion* value, + gpointer user_data); CoreTestsPigeonTestHostIntegrationCoreApiEchoAllNullableTypesResponse* ( *echo_all_nullable_types)(CoreTestsPigeonTestAllNullableTypes* everything, gpointer user_data); diff --git a/packages/pigeon/platform_tests/test_plugin/linux/test/equality_test.cc b/packages/pigeon/platform_tests/test_plugin/linux/test/equality_test.cc new file mode 100644 index 000000000000..349c4bdd34cb --- /dev/null +++ b/packages/pigeon/platform_tests/test_plugin/linux/test/equality_test.cc @@ -0,0 +1,238 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include + +#include + +#include "pigeon/core_tests.gen.h" + +static CoreTestsPigeonTestAllNullableTypes* create_empty_all_nullable_types() { + return core_tests_pigeon_test_all_nullable_types_new( + nullptr, nullptr, nullptr, nullptr, nullptr, 0, nullptr, 0, nullptr, 0, + nullptr, 0, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, + nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, + nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr); +} + +TEST(Equality, AllNullableTypesNaN) { + double nan_val = NAN; + g_autoptr(CoreTestsPigeonTestAllNullableTypes) all1 = + core_tests_pigeon_test_all_nullable_types_new( + nullptr, nullptr, nullptr, &nan_val, nullptr, 0, nullptr, 0, nullptr, + 0, nullptr, 0, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, + nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, + nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, + nullptr, nullptr, nullptr); + g_autoptr(CoreTestsPigeonTestAllNullableTypes) all2 = + core_tests_pigeon_test_all_nullable_types_new( + nullptr, nullptr, nullptr, &nan_val, nullptr, 0, nullptr, 0, nullptr, + 0, nullptr, 0, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, + nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, + nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, + nullptr, nullptr, nullptr); + + EXPECT_TRUE(core_tests_pigeon_test_all_nullable_types_equals(all1, all2)); + EXPECT_EQ(core_tests_pigeon_test_all_nullable_types_hash(all1), + core_tests_pigeon_test_all_nullable_types_hash(all2)); +} + +TEST(Equality, AllNullableTypesCollectionNaN) { + g_autoptr(FlValue) list1 = fl_value_new_list(); + fl_value_append_take(list1, fl_value_new_float(NAN)); + + g_autoptr(FlValue) list2 = fl_value_new_list(); + fl_value_append_take(list2, fl_value_new_float(NAN)); + + g_autoptr(CoreTestsPigeonTestAllNullableTypes) all1 = + core_tests_pigeon_test_all_nullable_types_new( + nullptr, nullptr, nullptr, nullptr, nullptr, 0, nullptr, 0, nullptr, + 0, nullptr, 0, nullptr, nullptr, nullptr, nullptr, nullptr, list1, + nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, + nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, + nullptr, nullptr, nullptr); + g_autoptr(CoreTestsPigeonTestAllNullableTypes) all2 = + core_tests_pigeon_test_all_nullable_types_new( + nullptr, nullptr, nullptr, nullptr, nullptr, 0, nullptr, 0, nullptr, + 0, nullptr, 0, nullptr, nullptr, nullptr, nullptr, nullptr, list2, + nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, + nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, + nullptr, nullptr, nullptr); + + EXPECT_TRUE(core_tests_pigeon_test_all_nullable_types_equals(all1, all2)); + EXPECT_EQ(core_tests_pigeon_test_all_nullable_types_hash(all1), + core_tests_pigeon_test_all_nullable_types_hash(all2)); +} + +TEST(Equality, AllNullableTypesRecursive) { + g_autoptr(CoreTestsPigeonTestAllNullableTypes) nested1 = + create_empty_all_nullable_types(); + g_autoptr(CoreTestsPigeonTestAllNullableTypes) all1 = + core_tests_pigeon_test_all_nullable_types_new( + nullptr, nullptr, nullptr, nullptr, nullptr, 0, nullptr, 0, nullptr, + 0, nullptr, 0, nullptr, nullptr, nullptr, nullptr, nested1, nullptr, + nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, + nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, + nullptr, nullptr, nullptr); + + g_autoptr(CoreTestsPigeonTestAllNullableTypes) nested2 = + create_empty_all_nullable_types(); + g_autoptr(CoreTestsPigeonTestAllNullableTypes) all2 = + core_tests_pigeon_test_all_nullable_types_new( + nullptr, nullptr, nullptr, nullptr, nullptr, 0, nullptr, 0, nullptr, + 0, nullptr, 0, nullptr, nullptr, nullptr, nullptr, nested2, nullptr, + nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, + nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, + nullptr, nullptr, nullptr); + + EXPECT_TRUE(core_tests_pigeon_test_all_nullable_types_equals(all1, all2)); + EXPECT_EQ(core_tests_pigeon_test_all_nullable_types_hash(all1), + core_tests_pigeon_test_all_nullable_types_hash(all2)); +} + +TEST(Equality, AllTypesNumericLists) { + uint8_t bytes[] = {1, 2, 3}; + int32_t ints32[] = {4, 5}; + double doubles[] = {1.1, 2.2}; + + g_autoptr(CoreTestsPigeonTestAllTypes) all1 = + core_tests_pigeon_test_all_types_new( + TRUE, 1, 2, 3.3, bytes, 3, ints32, 2, nullptr, 0, doubles, 2, + PIGEON_INTEGRATION_TESTS_AN_ENUM_ONE, + PIGEON_INTEGRATION_TESTS_ANOTHER_ENUM_JUST_IN_CASE, "hello", nullptr, + nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, + nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, + nullptr, nullptr); + + g_autoptr(CoreTestsPigeonTestAllTypes) all2 = + core_tests_pigeon_test_all_types_new( + TRUE, 1, 2, 3.3, bytes, 3, ints32, 2, nullptr, 0, doubles, 2, + PIGEON_INTEGRATION_TESTS_AN_ENUM_ONE, + PIGEON_INTEGRATION_TESTS_ANOTHER_ENUM_JUST_IN_CASE, "hello", nullptr, + nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, + nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, + nullptr, nullptr); + + EXPECT_TRUE(core_tests_pigeon_test_all_types_equals(all1, all2)); + EXPECT_EQ(core_tests_pigeon_test_all_types_hash(all1), + core_tests_pigeon_test_all_types_hash(all2)); + + // Change one element in a numeric list + doubles[1] = 2.3; + g_autoptr(CoreTestsPigeonTestAllTypes) all3 = + core_tests_pigeon_test_all_types_new( + TRUE, 1, 2, 3.3, bytes, 3, ints32, 2, nullptr, 0, doubles, 2, + PIGEON_INTEGRATION_TESTS_AN_ENUM_ONE, + PIGEON_INTEGRATION_TESTS_ANOTHER_ENUM_JUST_IN_CASE, "hello", nullptr, + nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, + nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, + nullptr, nullptr); + + EXPECT_FALSE(core_tests_pigeon_test_all_types_equals(all1, all3)); + EXPECT_NE(core_tests_pigeon_test_all_types_hash(all1), + core_tests_pigeon_test_all_types_hash(all3)); +} + +TEST(Equality, SignedZero) { + double p_zero = 0.0; + double n_zero = -0.0; + g_autoptr(CoreTestsPigeonTestAllNullableTypes) all1 = + core_tests_pigeon_test_all_nullable_types_new( + nullptr, nullptr, nullptr, &p_zero, nullptr, 0, nullptr, 0, nullptr, + 0, nullptr, 0, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, + nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, + nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, + nullptr, nullptr, nullptr); + g_autoptr(CoreTestsPigeonTestAllNullableTypes) all2 = + core_tests_pigeon_test_all_nullable_types_new( + nullptr, nullptr, nullptr, &n_zero, nullptr, 0, nullptr, 0, nullptr, + 0, nullptr, 0, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, + nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, + nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, + nullptr, nullptr, nullptr); + + EXPECT_TRUE(core_tests_pigeon_test_all_nullable_types_equals(all1, all2)); + EXPECT_EQ(core_tests_pigeon_test_all_nullable_types_hash(all1), + core_tests_pigeon_test_all_nullable_types_hash(all2)); +} + +TEST(Equality, SignedZeroMapKey) { + double p_zero = 0.0; + double n_zero = -0.0; + g_autoptr(FlValue) map1 = fl_value_new_map(); + fl_value_set_take(map1, fl_value_new_float(p_zero), fl_value_new_string("a")); + g_autoptr(FlValue) map2 = fl_value_new_map(); + fl_value_set_take(map2, fl_value_new_float(n_zero), fl_value_new_string("a")); + + g_autoptr(CoreTestsPigeonTestAllNullableTypes) all1 = + core_tests_pigeon_test_all_nullable_types_new( + nullptr, nullptr, nullptr, nullptr, nullptr, 0, nullptr, 0, nullptr, + 0, nullptr, 0, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, + nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, + nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, map1, nullptr, + nullptr, nullptr); + g_autoptr(CoreTestsPigeonTestAllNullableTypes) all2 = + core_tests_pigeon_test_all_nullable_types_new( + nullptr, nullptr, nullptr, nullptr, nullptr, 0, nullptr, 0, nullptr, + 0, nullptr, 0, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, + nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, + nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, map2, nullptr, + nullptr, nullptr); + + EXPECT_TRUE(core_tests_pigeon_test_all_nullable_types_equals(all1, all2)); + EXPECT_EQ(core_tests_pigeon_test_all_nullable_types_hash(all1), + core_tests_pigeon_test_all_nullable_types_hash(all2)); +} + +TEST(Equality, SignedZeroList) { + g_autoptr(FlValue) list1 = fl_value_new_list(); + fl_value_append_take(list1, fl_value_new_float(0.0)); + g_autoptr(FlValue) list2 = fl_value_new_list(); + fl_value_append_take(list2, fl_value_new_float(-0.0)); + + g_autoptr(CoreTestsPigeonTestAllNullableTypes) all1 = + core_tests_pigeon_test_all_nullable_types_new( + nullptr, nullptr, nullptr, nullptr, nullptr, 0, nullptr, 0, nullptr, + 0, nullptr, 0, nullptr, nullptr, nullptr, nullptr, nullptr, list1, + nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, + nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, + nullptr, nullptr, nullptr); + g_autoptr(CoreTestsPigeonTestAllNullableTypes) all2 = + core_tests_pigeon_test_all_nullable_types_new( + nullptr, nullptr, nullptr, nullptr, nullptr, 0, nullptr, 0, nullptr, + 0, nullptr, 0, nullptr, nullptr, nullptr, nullptr, nullptr, list2, + nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, + nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, + nullptr, nullptr, nullptr); + + EXPECT_TRUE(core_tests_pigeon_test_all_nullable_types_equals(all1, all2)); + EXPECT_EQ(core_tests_pigeon_test_all_nullable_types_hash(all1), + core_tests_pigeon_test_all_nullable_types_hash(all2)); +} + +TEST(Equality, SignedZeroMapValue) { + g_autoptr(FlValue) map1 = fl_value_new_map(); + fl_value_set_take(map1, fl_value_new_string("a"), fl_value_new_float(0.0)); + g_autoptr(FlValue) map2 = fl_value_new_map(); + fl_value_set_take(map2, fl_value_new_string("a"), fl_value_new_float(-0.0)); + + g_autoptr(CoreTestsPigeonTestAllNullableTypes) all1 = + core_tests_pigeon_test_all_nullable_types_new( + nullptr, nullptr, nullptr, nullptr, nullptr, 0, nullptr, 0, nullptr, + 0, nullptr, 0, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, + nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, + nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, map1, nullptr, + nullptr, nullptr); + g_autoptr(CoreTestsPigeonTestAllNullableTypes) all2 = + core_tests_pigeon_test_all_nullable_types_new( + nullptr, nullptr, nullptr, nullptr, nullptr, 0, nullptr, 0, nullptr, + 0, nullptr, 0, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, + nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, + nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, map2, nullptr, + nullptr, nullptr); + + EXPECT_TRUE(core_tests_pigeon_test_all_nullable_types_equals(all1, all2)); + EXPECT_EQ(core_tests_pigeon_test_all_nullable_types_hash(all1), + core_tests_pigeon_test_all_nullable_types_hash(all2)); +} diff --git a/packages/pigeon/platform_tests/test_plugin/linux/test_plugin.cc b/packages/pigeon/platform_tests/test_plugin/linux/test_plugin.cc index 95c7aa410da0..693bb17eefee 100644 --- a/packages/pigeon/platform_tests/test_plugin/linux/test_plugin.cc +++ b/packages/pigeon/platform_tests/test_plugin/linux/test_plugin.cc @@ -253,6 +253,29 @@ echo_all_nullable_types(CoreTestsPigeonTestAllNullableTypes* everything, everything); } +static CoreTestsPigeonTestHostIntegrationCoreApiAreAllNullableTypesEqualResponse* +are_all_nullable_types_equal(CoreTestsPigeonTestAllNullableTypes* a, + CoreTestsPigeonTestAllNullableTypes* b, + gpointer user_data) { + return core_tests_pigeon_test_host_integration_core_api_are_all_nullable_types_equal_response_new( + core_tests_pigeon_test_all_nullable_types_equals(a, b)); +} + +static CoreTestsPigeonTestHostIntegrationCoreApiGetAllNullableTypesHashResponse* +get_all_nullable_types_hash(CoreTestsPigeonTestAllNullableTypes* value, + gpointer user_data) { + return core_tests_pigeon_test_host_integration_core_api_get_all_nullable_types_hash_response_new( + core_tests_pigeon_test_all_nullable_types_hash(value)); +} + +static CoreTestsPigeonTestHostIntegrationCoreApiGetAllNullableTypesWithoutRecursionHashResponse* +get_all_nullable_types_without_recursion_hash( + CoreTestsPigeonTestAllNullableTypesWithoutRecursion* value, + gpointer user_data) { + return core_tests_pigeon_test_host_integration_core_api_get_all_nullable_types_without_recursion_hash_response_new( + core_tests_pigeon_test_all_nullable_types_without_recursion_hash(value)); +} + static CoreTestsPigeonTestHostIntegrationCoreApiEchoAllNullableTypesWithoutRecursionResponse* echo_all_nullable_types_without_recursion( @@ -3224,6 +3247,10 @@ static CoreTestsPigeonTestHostIntegrationCoreApiVTable host_core_api_vtable = { .echo_named_default_string = echo_named_default_string, .echo_optional_default_double = echo_optional_default_double, .echo_required_int = echo_required_int, + .are_all_nullable_types_equal = are_all_nullable_types_equal, + .get_all_nullable_types_hash = get_all_nullable_types_hash, + .get_all_nullable_types_without_recursion_hash = + get_all_nullable_types_without_recursion_hash, .echo_all_nullable_types = echo_all_nullable_types, .echo_all_nullable_types_without_recursion = echo_all_nullable_types_without_recursion, diff --git a/packages/pigeon/platform_tests/test_plugin/windows/CMakeLists.txt b/packages/pigeon/platform_tests/test_plugin/windows/CMakeLists.txt index e69e6bc75130..fff3f37c5d5c 100644 --- a/packages/pigeon/platform_tests/test_plugin/windows/CMakeLists.txt +++ b/packages/pigeon/platform_tests/test_plugin/windows/CMakeLists.txt @@ -66,6 +66,9 @@ target_link_libraries(${PLUGIN_NAME} PRIVATE flutter flutter_wrapper_plugin) # https://developercommunity.visualstudio.com/t/stdany-doesnt-link-when-exceptions-are-disabled/376072 # TODO(stuartmorgan): Remove this once CI is using VS 2022 or later. target_compile_definitions(${PLUGIN_NAME} PRIVATE "_HAS_EXCEPTIONS=1") +if (MSVC) + target_compile_options(${PLUGIN_NAME} PRIVATE "/bigobj") +endif() # List of absolute paths to libraries that should be bundled with the plugin. # This list could contain prebuilt libraries, or libraries created by an @@ -126,6 +129,9 @@ add_custom_command(TARGET ${TEST_RUNNER} POST_BUILD # https://developercommunity.visualstudio.com/t/stdany-doesnt-link-when-exceptions-are-disabled/376072 # TODO(stuartmorgan): Remove this once CI is using VS 2022 or later. target_compile_definitions(${TEST_RUNNER} PRIVATE "_HAS_EXCEPTIONS=1") +if (MSVC) + target_compile_options(${TEST_RUNNER} PRIVATE "/bigobj") +endif() include(GoogleTest) gtest_discover_tests(${TEST_RUNNER}) diff --git a/packages/pigeon/platform_tests/test_plugin/windows/pigeon/core_tests.gen.cpp b/packages/pigeon/platform_tests/test_plugin/windows/pigeon/core_tests.gen.cpp index b8c9e6860572..f50c8eff918c 100644 --- a/packages/pigeon/platform_tests/test_plugin/windows/pigeon/core_tests.gen.cpp +++ b/packages/pigeon/platform_tests/test_plugin/windows/pigeon/core_tests.gen.cpp @@ -14,16 +14,18 @@ #include #include +#include +#include #include #include #include namespace core_tests_pigeontest { -using flutter::BasicMessageChannel; -using flutter::CustomEncodableValue; -using flutter::EncodableList; -using flutter::EncodableMap; -using flutter::EncodableValue; +using ::flutter::BasicMessageChannel; +using ::flutter::CustomEncodableValue; +using ::flutter::EncodableList; +using ::flutter::EncodableMap; +using ::flutter::EncodableValue; FlutterError CreateConnectionError(const std::string channel_name) { return FlutterError( @@ -32,6 +34,212 @@ FlutterError CreateConnectionError(const std::string channel_name) { EncodableValue("")); } +namespace { +template +bool PigeonInternalDeepEquals(const T& a, const T& b); + +bool PigeonInternalDeepEquals(const double& a, const double& b); + +template +bool PigeonInternalDeepEquals(const std::vector& a, const std::vector& b); + +template +bool PigeonInternalDeepEquals(const std::map& a, const std::map& b); + +template +bool PigeonInternalDeepEquals(const std::optional& a, + const std::optional& b); + +template +bool PigeonInternalDeepEquals(const std::unique_ptr& a, + const std::unique_ptr& b); + +bool PigeonInternalDeepEquals(const ::flutter::EncodableValue& a, + const ::flutter::EncodableValue& b); + +template +bool PigeonInternalDeepEquals(const T& a, const T& b) { + return a == b; +} + +template +bool PigeonInternalDeepEquals(const std::vector& a, + const std::vector& b) { + if (a.size() != b.size()) { + return false; + } + for (size_t i = 0; i < a.size(); ++i) { + if (!PigeonInternalDeepEquals(a[i], b[i])) { + return false; + } + } + return true; +} + +template +bool PigeonInternalDeepEquals(const std::map& a, + const std::map& b) { + if (a.size() != b.size()) { + return false; + } + for (const auto& kv : a) { + bool found = false; + for (const auto& b_kv : b) { + if (PigeonInternalDeepEquals(kv.first, b_kv.first)) { + if (PigeonInternalDeepEquals(kv.second, b_kv.second)) { + found = true; + break; + } else { + return false; + } + } + } + if (!found) { + return false; + } + } + return true; +} + +bool PigeonInternalDeepEquals(const double& a, const double& b) { + // Normalize -0.0 to 0.0 and handle NaN equality. + return (a == b) || (std::isnan(a) && std::isnan(b)); +} + +template +bool PigeonInternalDeepEquals(const std::optional& a, + const std::optional& b) { + if (!a && !b) { + return true; + } + if (!a || !b) { + return false; + } + return PigeonInternalDeepEquals(*a, *b); +} + +template +bool PigeonInternalDeepEquals(const std::unique_ptr& a, + const std::unique_ptr& b) { + if (a.get() == b.get()) { + return true; + } + if (!a || !b) { + return false; + } + return PigeonInternalDeepEquals(*a, *b); +} + +bool PigeonInternalDeepEquals(const ::flutter::EncodableValue& a, + const ::flutter::EncodableValue& b) { + if (a.index() != b.index()) { + return false; + } + if (const double* da = std::get_if(&a)) { + return PigeonInternalDeepEquals(*da, std::get(b)); + } else if (const ::flutter::EncodableList* la = + std::get_if<::flutter::EncodableList>(&a)) { + return PigeonInternalDeepEquals(*la, std::get<::flutter::EncodableList>(b)); + } else if (const ::flutter::EncodableMap* ma = + std::get_if<::flutter::EncodableMap>(&a)) { + return PigeonInternalDeepEquals(*ma, std::get<::flutter::EncodableMap>(b)); + } + return a == b; +} + +template +size_t PigeonInternalDeepHash(const T& v); + +size_t PigeonInternalDeepHash(const double& v); + +template +size_t PigeonInternalDeepHash(const std::vector& v); + +template +size_t PigeonInternalDeepHash(const std::map& v); + +template +size_t PigeonInternalDeepHash(const std::optional& v); + +template +size_t PigeonInternalDeepHash(const std::unique_ptr& v); + +size_t PigeonInternalDeepHash(const ::flutter::EncodableValue& v); + +template +size_t PigeonInternalDeepHash(const T& v) { + return std::hash()(v); +} + +template +size_t PigeonInternalDeepHash(const std::vector& v) { + size_t result = 1; + for (const auto& item : v) { + result = result * 31 + PigeonInternalDeepHash(item); + } + return result; +} + +template +size_t PigeonInternalDeepHash(const std::map& v) { + size_t result = 0; + for (const auto& kv : v) { + result += ((PigeonInternalDeepHash(kv.first) * 31) ^ + PigeonInternalDeepHash(kv.second)); + } + return result; +} + +size_t PigeonInternalDeepHash(const double& v) { + if (std::isnan(v)) { + // Normalize NaN to a consistent hash. + return std::hash()(std::numeric_limits::quiet_NaN()); + } + if (v == 0.0) { + // Normalize -0.0 to 0.0 so they have the same hash code. + return std::hash()(0.0); + } + return std::hash()(v); +} + +template +size_t PigeonInternalDeepHash(const std::optional& v) { + return v ? PigeonInternalDeepHash(*v) : 0; +} + +template +size_t PigeonInternalDeepHash(const std::unique_ptr& v) { + return v ? PigeonInternalDeepHash(*v) : 0; +} + +size_t PigeonInternalDeepHash(const ::flutter::EncodableValue& v) { + size_t result = v.index(); + if (const double* dv = std::get_if(&v)) { + result = result * 31 + PigeonInternalDeepHash(*dv); + } else if (const ::flutter::EncodableList* lv = + std::get_if<::flutter::EncodableList>(&v)) { + result = result * 31 + PigeonInternalDeepHash(*lv); + } else if (const ::flutter::EncodableMap* mv = + std::get_if<::flutter::EncodableMap>(&v)) { + result = result * 31 + PigeonInternalDeepHash(*mv); + } else { + std::visit( + [&result](const auto& val) { + using T = std::decay_t; + if constexpr (!std::is_same_v && + !std::is_same_v && + !std::is_same_v && + !std::is_same_v && + !std::is_same_v) { + result = result * 31 + PigeonInternalDeepHash(val); + } + }, + v); + } + return result; +} + +} // namespace // UnusedClass UnusedClass::UnusedClass() {} @@ -69,6 +277,22 @@ UnusedClass UnusedClass::FromEncodableList(const EncodableList& list) { return decoded; } +bool UnusedClass::operator==(const UnusedClass& other) const { + return PigeonInternalDeepEquals(a_field_, other.a_field_); +} + +bool UnusedClass::operator!=(const UnusedClass& other) const { + return !(*this == other); +} + +size_t UnusedClass::Hash() const { + size_t result = 1; + result = result * 31 + PigeonInternalDeepHash(a_field_); + return result; +} + +size_t PigeonInternalDeepHash(const UnusedClass& v) { return v.Hash(); } + // AllTypes AllTypes::AllTypes(bool a_bool, int64_t an_int, int64_t an_int64, @@ -337,6 +561,76 @@ AllTypes AllTypes::FromEncodableList(const EncodableList& list) { return decoded; } +bool AllTypes::operator==(const AllTypes& other) const { + return PigeonInternalDeepEquals(a_bool_, other.a_bool_) && + PigeonInternalDeepEquals(an_int_, other.an_int_) && + PigeonInternalDeepEquals(an_int64_, other.an_int64_) && + PigeonInternalDeepEquals(a_double_, other.a_double_) && + PigeonInternalDeepEquals(a_byte_array_, other.a_byte_array_) && + PigeonInternalDeepEquals(a4_byte_array_, other.a4_byte_array_) && + PigeonInternalDeepEquals(a8_byte_array_, other.a8_byte_array_) && + PigeonInternalDeepEquals(a_float_array_, other.a_float_array_) && + PigeonInternalDeepEquals(an_enum_, other.an_enum_) && + PigeonInternalDeepEquals(another_enum_, other.another_enum_) && + PigeonInternalDeepEquals(a_string_, other.a_string_) && + PigeonInternalDeepEquals(an_object_, other.an_object_) && + PigeonInternalDeepEquals(list_, other.list_) && + PigeonInternalDeepEquals(string_list_, other.string_list_) && + PigeonInternalDeepEquals(int_list_, other.int_list_) && + PigeonInternalDeepEquals(double_list_, other.double_list_) && + PigeonInternalDeepEquals(bool_list_, other.bool_list_) && + PigeonInternalDeepEquals(enum_list_, other.enum_list_) && + PigeonInternalDeepEquals(object_list_, other.object_list_) && + PigeonInternalDeepEquals(list_list_, other.list_list_) && + PigeonInternalDeepEquals(map_list_, other.map_list_) && + PigeonInternalDeepEquals(map_, other.map_) && + PigeonInternalDeepEquals(string_map_, other.string_map_) && + PigeonInternalDeepEquals(int_map_, other.int_map_) && + PigeonInternalDeepEquals(enum_map_, other.enum_map_) && + PigeonInternalDeepEquals(object_map_, other.object_map_) && + PigeonInternalDeepEquals(list_map_, other.list_map_) && + PigeonInternalDeepEquals(map_map_, other.map_map_); +} + +bool AllTypes::operator!=(const AllTypes& other) const { + return !(*this == other); +} + +size_t AllTypes::Hash() const { + size_t result = 1; + result = result * 31 + PigeonInternalDeepHash(a_bool_); + result = result * 31 + PigeonInternalDeepHash(an_int_); + result = result * 31 + PigeonInternalDeepHash(an_int64_); + result = result * 31 + PigeonInternalDeepHash(a_double_); + result = result * 31 + PigeonInternalDeepHash(a_byte_array_); + result = result * 31 + PigeonInternalDeepHash(a4_byte_array_); + result = result * 31 + PigeonInternalDeepHash(a8_byte_array_); + result = result * 31 + PigeonInternalDeepHash(a_float_array_); + result = result * 31 + PigeonInternalDeepHash(an_enum_); + result = result * 31 + PigeonInternalDeepHash(another_enum_); + result = result * 31 + PigeonInternalDeepHash(a_string_); + result = result * 31 + PigeonInternalDeepHash(an_object_); + result = result * 31 + PigeonInternalDeepHash(list_); + result = result * 31 + PigeonInternalDeepHash(string_list_); + result = result * 31 + PigeonInternalDeepHash(int_list_); + result = result * 31 + PigeonInternalDeepHash(double_list_); + result = result * 31 + PigeonInternalDeepHash(bool_list_); + result = result * 31 + PigeonInternalDeepHash(enum_list_); + result = result * 31 + PigeonInternalDeepHash(object_list_); + result = result * 31 + PigeonInternalDeepHash(list_list_); + result = result * 31 + PigeonInternalDeepHash(map_list_); + result = result * 31 + PigeonInternalDeepHash(map_); + result = result * 31 + PigeonInternalDeepHash(string_map_); + result = result * 31 + PigeonInternalDeepHash(int_map_); + result = result * 31 + PigeonInternalDeepHash(enum_map_); + result = result * 31 + PigeonInternalDeepHash(object_map_); + result = result * 31 + PigeonInternalDeepHash(list_map_); + result = result * 31 + PigeonInternalDeepHash(map_map_); + return result; +} + +size_t PigeonInternalDeepHash(const AllTypes& v) { return v.Hash(); } + // AllNullableTypes AllNullableTypes::AllNullableTypes() {} @@ -1187,6 +1481,93 @@ AllNullableTypes AllNullableTypes::FromEncodableList( return decoded; } +bool AllNullableTypes::operator==(const AllNullableTypes& other) const { + return PigeonInternalDeepEquals(a_nullable_bool_, other.a_nullable_bool_) && + PigeonInternalDeepEquals(a_nullable_int_, other.a_nullable_int_) && + PigeonInternalDeepEquals(a_nullable_int64_, other.a_nullable_int64_) && + PigeonInternalDeepEquals(a_nullable_double_, + other.a_nullable_double_) && + PigeonInternalDeepEquals(a_nullable_byte_array_, + other.a_nullable_byte_array_) && + PigeonInternalDeepEquals(a_nullable4_byte_array_, + other.a_nullable4_byte_array_) && + PigeonInternalDeepEquals(a_nullable8_byte_array_, + other.a_nullable8_byte_array_) && + PigeonInternalDeepEquals(a_nullable_float_array_, + other.a_nullable_float_array_) && + PigeonInternalDeepEquals(a_nullable_enum_, other.a_nullable_enum_) && + PigeonInternalDeepEquals(another_nullable_enum_, + other.another_nullable_enum_) && + PigeonInternalDeepEquals(a_nullable_string_, + other.a_nullable_string_) && + PigeonInternalDeepEquals(a_nullable_object_, + other.a_nullable_object_) && + PigeonInternalDeepEquals(all_nullable_types_, + other.all_nullable_types_) && + PigeonInternalDeepEquals(list_, other.list_) && + PigeonInternalDeepEquals(string_list_, other.string_list_) && + PigeonInternalDeepEquals(int_list_, other.int_list_) && + PigeonInternalDeepEquals(double_list_, other.double_list_) && + PigeonInternalDeepEquals(bool_list_, other.bool_list_) && + PigeonInternalDeepEquals(enum_list_, other.enum_list_) && + PigeonInternalDeepEquals(object_list_, other.object_list_) && + PigeonInternalDeepEquals(list_list_, other.list_list_) && + PigeonInternalDeepEquals(map_list_, other.map_list_) && + PigeonInternalDeepEquals(recursive_class_list_, + other.recursive_class_list_) && + PigeonInternalDeepEquals(map_, other.map_) && + PigeonInternalDeepEquals(string_map_, other.string_map_) && + PigeonInternalDeepEquals(int_map_, other.int_map_) && + PigeonInternalDeepEquals(enum_map_, other.enum_map_) && + PigeonInternalDeepEquals(object_map_, other.object_map_) && + PigeonInternalDeepEquals(list_map_, other.list_map_) && + PigeonInternalDeepEquals(map_map_, other.map_map_) && + PigeonInternalDeepEquals(recursive_class_map_, + other.recursive_class_map_); +} + +bool AllNullableTypes::operator!=(const AllNullableTypes& other) const { + return !(*this == other); +} + +size_t AllNullableTypes::Hash() const { + size_t result = 1; + result = result * 31 + PigeonInternalDeepHash(a_nullable_bool_); + result = result * 31 + PigeonInternalDeepHash(a_nullable_int_); + result = result * 31 + PigeonInternalDeepHash(a_nullable_int64_); + result = result * 31 + PigeonInternalDeepHash(a_nullable_double_); + result = result * 31 + PigeonInternalDeepHash(a_nullable_byte_array_); + result = result * 31 + PigeonInternalDeepHash(a_nullable4_byte_array_); + result = result * 31 + PigeonInternalDeepHash(a_nullable8_byte_array_); + result = result * 31 + PigeonInternalDeepHash(a_nullable_float_array_); + result = result * 31 + PigeonInternalDeepHash(a_nullable_enum_); + result = result * 31 + PigeonInternalDeepHash(another_nullable_enum_); + result = result * 31 + PigeonInternalDeepHash(a_nullable_string_); + result = result * 31 + PigeonInternalDeepHash(a_nullable_object_); + result = result * 31 + PigeonInternalDeepHash(all_nullable_types_); + result = result * 31 + PigeonInternalDeepHash(list_); + result = result * 31 + PigeonInternalDeepHash(string_list_); + result = result * 31 + PigeonInternalDeepHash(int_list_); + result = result * 31 + PigeonInternalDeepHash(double_list_); + result = result * 31 + PigeonInternalDeepHash(bool_list_); + result = result * 31 + PigeonInternalDeepHash(enum_list_); + result = result * 31 + PigeonInternalDeepHash(object_list_); + result = result * 31 + PigeonInternalDeepHash(list_list_); + result = result * 31 + PigeonInternalDeepHash(map_list_); + result = result * 31 + PigeonInternalDeepHash(recursive_class_list_); + result = result * 31 + PigeonInternalDeepHash(map_); + result = result * 31 + PigeonInternalDeepHash(string_map_); + result = result * 31 + PigeonInternalDeepHash(int_map_); + result = result * 31 + PigeonInternalDeepHash(enum_map_); + result = result * 31 + PigeonInternalDeepHash(object_map_); + result = result * 31 + PigeonInternalDeepHash(list_map_); + result = result * 31 + PigeonInternalDeepHash(map_map_); + result = result * 31 + PigeonInternalDeepHash(recursive_class_map_); + return result; +} + +size_t PigeonInternalDeepHash(const AllNullableTypes& v) { return v.Hash(); } + // AllNullableTypesWithoutRecursion AllNullableTypesWithoutRecursion::AllNullableTypesWithoutRecursion() {} @@ -1873,6 +2254,88 @@ AllNullableTypesWithoutRecursion::FromEncodableList(const EncodableList& list) { return decoded; } +bool AllNullableTypesWithoutRecursion::operator==( + const AllNullableTypesWithoutRecursion& other) const { + return PigeonInternalDeepEquals(a_nullable_bool_, other.a_nullable_bool_) && + PigeonInternalDeepEquals(a_nullable_int_, other.a_nullable_int_) && + PigeonInternalDeepEquals(a_nullable_int64_, other.a_nullable_int64_) && + PigeonInternalDeepEquals(a_nullable_double_, + other.a_nullable_double_) && + PigeonInternalDeepEquals(a_nullable_byte_array_, + other.a_nullable_byte_array_) && + PigeonInternalDeepEquals(a_nullable4_byte_array_, + other.a_nullable4_byte_array_) && + PigeonInternalDeepEquals(a_nullable8_byte_array_, + other.a_nullable8_byte_array_) && + PigeonInternalDeepEquals(a_nullable_float_array_, + other.a_nullable_float_array_) && + PigeonInternalDeepEquals(a_nullable_enum_, other.a_nullable_enum_) && + PigeonInternalDeepEquals(another_nullable_enum_, + other.another_nullable_enum_) && + PigeonInternalDeepEquals(a_nullable_string_, + other.a_nullable_string_) && + PigeonInternalDeepEquals(a_nullable_object_, + other.a_nullable_object_) && + PigeonInternalDeepEquals(list_, other.list_) && + PigeonInternalDeepEquals(string_list_, other.string_list_) && + PigeonInternalDeepEquals(int_list_, other.int_list_) && + PigeonInternalDeepEquals(double_list_, other.double_list_) && + PigeonInternalDeepEquals(bool_list_, other.bool_list_) && + PigeonInternalDeepEquals(enum_list_, other.enum_list_) && + PigeonInternalDeepEquals(object_list_, other.object_list_) && + PigeonInternalDeepEquals(list_list_, other.list_list_) && + PigeonInternalDeepEquals(map_list_, other.map_list_) && + PigeonInternalDeepEquals(map_, other.map_) && + PigeonInternalDeepEquals(string_map_, other.string_map_) && + PigeonInternalDeepEquals(int_map_, other.int_map_) && + PigeonInternalDeepEquals(enum_map_, other.enum_map_) && + PigeonInternalDeepEquals(object_map_, other.object_map_) && + PigeonInternalDeepEquals(list_map_, other.list_map_) && + PigeonInternalDeepEquals(map_map_, other.map_map_); +} + +bool AllNullableTypesWithoutRecursion::operator!=( + const AllNullableTypesWithoutRecursion& other) const { + return !(*this == other); +} + +size_t AllNullableTypesWithoutRecursion::Hash() const { + size_t result = 1; + result = result * 31 + PigeonInternalDeepHash(a_nullable_bool_); + result = result * 31 + PigeonInternalDeepHash(a_nullable_int_); + result = result * 31 + PigeonInternalDeepHash(a_nullable_int64_); + result = result * 31 + PigeonInternalDeepHash(a_nullable_double_); + result = result * 31 + PigeonInternalDeepHash(a_nullable_byte_array_); + result = result * 31 + PigeonInternalDeepHash(a_nullable4_byte_array_); + result = result * 31 + PigeonInternalDeepHash(a_nullable8_byte_array_); + result = result * 31 + PigeonInternalDeepHash(a_nullable_float_array_); + result = result * 31 + PigeonInternalDeepHash(a_nullable_enum_); + result = result * 31 + PigeonInternalDeepHash(another_nullable_enum_); + result = result * 31 + PigeonInternalDeepHash(a_nullable_string_); + result = result * 31 + PigeonInternalDeepHash(a_nullable_object_); + result = result * 31 + PigeonInternalDeepHash(list_); + result = result * 31 + PigeonInternalDeepHash(string_list_); + result = result * 31 + PigeonInternalDeepHash(int_list_); + result = result * 31 + PigeonInternalDeepHash(double_list_); + result = result * 31 + PigeonInternalDeepHash(bool_list_); + result = result * 31 + PigeonInternalDeepHash(enum_list_); + result = result * 31 + PigeonInternalDeepHash(object_list_); + result = result * 31 + PigeonInternalDeepHash(list_list_); + result = result * 31 + PigeonInternalDeepHash(map_list_); + result = result * 31 + PigeonInternalDeepHash(map_); + result = result * 31 + PigeonInternalDeepHash(string_map_); + result = result * 31 + PigeonInternalDeepHash(int_map_); + result = result * 31 + PigeonInternalDeepHash(enum_map_); + result = result * 31 + PigeonInternalDeepHash(object_map_); + result = result * 31 + PigeonInternalDeepHash(list_map_); + result = result * 31 + PigeonInternalDeepHash(map_map_); + return result; +} + +size_t PigeonInternalDeepHash(const AllNullableTypesWithoutRecursion& v) { + return v.Hash(); +} + // AllClassesWrapper AllClassesWrapper::AllClassesWrapper(const AllNullableTypes& all_nullable_types, @@ -2079,6 +2542,40 @@ AllClassesWrapper AllClassesWrapper::FromEncodableList( return decoded; } +bool AllClassesWrapper::operator==(const AllClassesWrapper& other) const { + return PigeonInternalDeepEquals(all_nullable_types_, + other.all_nullable_types_) && + PigeonInternalDeepEquals( + all_nullable_types_without_recursion_, + other.all_nullable_types_without_recursion_) && + PigeonInternalDeepEquals(all_types_, other.all_types_) && + PigeonInternalDeepEquals(class_list_, other.class_list_) && + PigeonInternalDeepEquals(nullable_class_list_, + other.nullable_class_list_) && + PigeonInternalDeepEquals(class_map_, other.class_map_) && + PigeonInternalDeepEquals(nullable_class_map_, + other.nullable_class_map_); +} + +bool AllClassesWrapper::operator!=(const AllClassesWrapper& other) const { + return !(*this == other); +} + +size_t AllClassesWrapper::Hash() const { + size_t result = 1; + result = result * 31 + PigeonInternalDeepHash(all_nullable_types_); + result = result * 31 + + PigeonInternalDeepHash(all_nullable_types_without_recursion_); + result = result * 31 + PigeonInternalDeepHash(all_types_); + result = result * 31 + PigeonInternalDeepHash(class_list_); + result = result * 31 + PigeonInternalDeepHash(nullable_class_list_); + result = result * 31 + PigeonInternalDeepHash(class_map_); + result = result * 31 + PigeonInternalDeepHash(nullable_class_map_); + return result; +} + +size_t PigeonInternalDeepHash(const AllClassesWrapper& v) { return v.Hash(); } + // TestMessage TestMessage::TestMessage() {} @@ -2116,10 +2613,26 @@ TestMessage TestMessage::FromEncodableList(const EncodableList& list) { return decoded; } +bool TestMessage::operator==(const TestMessage& other) const { + return PigeonInternalDeepEquals(test_list_, other.test_list_); +} + +bool TestMessage::operator!=(const TestMessage& other) const { + return !(*this == other); +} + +size_t TestMessage::Hash() const { + size_t result = 1; + result = result * 31 + PigeonInternalDeepHash(test_list_); + return result; +} + +size_t PigeonInternalDeepHash(const TestMessage& v) { return v.Hash(); } + PigeonInternalCodecSerializer::PigeonInternalCodecSerializer() {} EncodableValue PigeonInternalCodecSerializer::ReadValueOfType( - uint8_t type, flutter::ByteStreamReader* stream) const { + uint8_t type, ::flutter::ByteStreamReader* stream) const { switch (type) { case 129: { const auto& encodable_enum_arg = ReadValue(stream); @@ -2164,12 +2677,12 @@ EncodableValue PigeonInternalCodecSerializer::ReadValueOfType( std::get(ReadValue(stream)))); } default: - return flutter::StandardCodecSerializer::ReadValueOfType(type, stream); + return ::flutter::StandardCodecSerializer::ReadValueOfType(type, stream); } } void PigeonInternalCodecSerializer::WriteValue( - const EncodableValue& value, flutter::ByteStreamWriter* stream) const { + const EncodableValue& value, ::flutter::ByteStreamWriter* stream) const { if (const CustomEncodableValue* custom_value = std::get_if(&value)) { if (custom_value->type() == typeid(AnEnum)) { @@ -2233,23 +2746,23 @@ void PigeonInternalCodecSerializer::WriteValue( return; } } - flutter::StandardCodecSerializer::WriteValue(value, stream); + ::flutter::StandardCodecSerializer::WriteValue(value, stream); } /// The codec used by HostIntegrationCoreApi. -const flutter::StandardMessageCodec& HostIntegrationCoreApi::GetCodec() { - return flutter::StandardMessageCodec::GetInstance( +const ::flutter::StandardMessageCodec& HostIntegrationCoreApi::GetCodec() { + return ::flutter::StandardMessageCodec::GetInstance( &PigeonInternalCodecSerializer::GetInstance()); } // Sets up an instance of `HostIntegrationCoreApi` to handle messages through // the `binary_messenger`. -void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, +void HostIntegrationCoreApi::SetUp(::flutter::BinaryMessenger* binary_messenger, HostIntegrationCoreApi* api) { HostIntegrationCoreApi::SetUp(binary_messenger, api, ""); } -void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, +void HostIntegrationCoreApi::SetUp(::flutter::BinaryMessenger* binary_messenger, HostIntegrationCoreApi* api, const std::string& message_channel_suffix) { const std::string prepended_suffix = @@ -2265,7 +2778,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { std::optional output = api->Noop(); if (output.has_value()) { @@ -2292,7 +2805,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_everything_arg = args.at(0); @@ -2328,7 +2841,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { ErrorOr> output = api->ThrowError(); if (output.has_error()) { @@ -2361,7 +2874,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { std::optional output = api->ThrowErrorFromVoid(); if (output.has_value()) { @@ -2388,7 +2901,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { ErrorOr> output = api->ThrowFlutterError(); @@ -2422,7 +2935,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_an_int_arg = args.at(0); @@ -2456,7 +2969,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_a_double_arg = args.at(0); @@ -2491,7 +3004,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_a_bool_arg = args.at(0); @@ -2525,7 +3038,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_a_string_arg = args.at(0); @@ -2560,7 +3073,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_a_uint8_list_arg = args.at(0); @@ -2596,7 +3109,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_an_object_arg = args.at(0); @@ -2630,7 +3143,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_list_arg = args.at(0); @@ -2665,7 +3178,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_enum_list_arg = args.at(0); @@ -2700,7 +3213,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_class_list_arg = args.at(0); @@ -2736,7 +3249,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_enum_list_arg = args.at(0); @@ -2773,7 +3286,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_class_list_arg = args.at(0); @@ -2809,7 +3322,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_map_arg = args.at(0); @@ -2843,7 +3356,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_string_map_arg = args.at(0); @@ -2878,7 +3391,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_int_map_arg = args.at(0); @@ -2913,7 +3426,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_enum_map_arg = args.at(0); @@ -2948,7 +3461,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_class_map_arg = args.at(0); @@ -2984,7 +3497,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_string_map_arg = args.at(0); @@ -3020,7 +3533,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_int_map_arg = args.at(0); @@ -3056,7 +3569,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_enum_map_arg = args.at(0); @@ -3092,7 +3605,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_class_map_arg = args.at(0); @@ -3128,7 +3641,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_wrapper_arg = args.at(0); @@ -3165,7 +3678,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_an_enum_arg = args.at(0); @@ -3201,7 +3714,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_another_enum_arg = args.at(0); @@ -3239,7 +3752,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_a_string_arg = args.at(0); @@ -3276,7 +3789,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_a_double_arg = args.at(0); @@ -3312,7 +3825,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_an_int_arg = args.at(0); @@ -3337,6 +3850,124 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, channel.SetMessageHandler(nullptr); } } + { + BasicMessageChannel<> channel( + binary_messenger, + "dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi." + "areAllNullableTypesEqual" + + prepended_suffix, + &GetCodec()); + if (api != nullptr) { + channel.SetMessageHandler( + [api](const EncodableValue& message, + const ::flutter::MessageReply& reply) { + try { + const auto& args = std::get(message); + const auto& encodable_a_arg = args.at(0); + if (encodable_a_arg.IsNull()) { + reply(WrapError("a_arg unexpectedly null.")); + return; + } + const auto& a_arg = std::any_cast( + std::get(encodable_a_arg)); + const auto& encodable_b_arg = args.at(1); + if (encodable_b_arg.IsNull()) { + reply(WrapError("b_arg unexpectedly null.")); + return; + } + const auto& b_arg = std::any_cast( + std::get(encodable_b_arg)); + ErrorOr output = + api->AreAllNullableTypesEqual(a_arg, b_arg); + if (output.has_error()) { + reply(WrapError(output.error())); + return; + } + EncodableList wrapped; + wrapped.push_back(EncodableValue(std::move(output).TakeValue())); + reply(EncodableValue(std::move(wrapped))); + } catch (const std::exception& exception) { + reply(WrapError(exception.what())); + } + }); + } else { + channel.SetMessageHandler(nullptr); + } + } + { + BasicMessageChannel<> channel( + binary_messenger, + "dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi." + "getAllNullableTypesHash" + + prepended_suffix, + &GetCodec()); + if (api != nullptr) { + channel.SetMessageHandler( + [api](const EncodableValue& message, + const ::flutter::MessageReply& reply) { + try { + const auto& args = std::get(message); + const auto& encodable_value_arg = args.at(0); + if (encodable_value_arg.IsNull()) { + reply(WrapError("value_arg unexpectedly null.")); + return; + } + const auto& value_arg = std::any_cast( + std::get(encodable_value_arg)); + ErrorOr output = api->GetAllNullableTypesHash(value_arg); + if (output.has_error()) { + reply(WrapError(output.error())); + return; + } + EncodableList wrapped; + wrapped.push_back(EncodableValue(std::move(output).TakeValue())); + reply(EncodableValue(std::move(wrapped))); + } catch (const std::exception& exception) { + reply(WrapError(exception.what())); + } + }); + } else { + channel.SetMessageHandler(nullptr); + } + } + { + BasicMessageChannel<> channel( + binary_messenger, + "dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi." + "getAllNullableTypesWithoutRecursionHash" + + prepended_suffix, + &GetCodec()); + if (api != nullptr) { + channel.SetMessageHandler( + [api](const EncodableValue& message, + const ::flutter::MessageReply& reply) { + try { + const auto& args = std::get(message); + const auto& encodable_value_arg = args.at(0); + if (encodable_value_arg.IsNull()) { + reply(WrapError("value_arg unexpectedly null.")); + return; + } + const auto& value_arg = + std::any_cast( + std::get(encodable_value_arg)); + ErrorOr output = + api->GetAllNullableTypesWithoutRecursionHash(value_arg); + if (output.has_error()) { + reply(WrapError(output.error())); + return; + } + EncodableList wrapped; + wrapped.push_back(EncodableValue(std::move(output).TakeValue())); + reply(EncodableValue(std::move(wrapped))); + } catch (const std::exception& exception) { + reply(WrapError(exception.what())); + } + }); + } else { + channel.SetMessageHandler(nullptr); + } + } { BasicMessageChannel<> channel( binary_messenger, @@ -3347,7 +3978,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_everything_arg = args.at(0); @@ -3388,10 +4019,9 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, prepended_suffix, &GetCodec()); if (api != nullptr) { - channel.SetMessageHandler([api]( - const EncodableValue& message, - const flutter::MessageReply& - reply) { + channel.SetMessageHandler([api](const EncodableValue& message, + const ::flutter::MessageReply< + EncodableValue>& reply) { try { const auto& args = std::get(message); const auto& encodable_everything_arg = args.at(0); @@ -3434,7 +4064,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_wrapper_arg = args.at(0); @@ -3477,7 +4107,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_nullable_string_arg = args.at(0); @@ -3511,7 +4141,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_a_nullable_bool_arg = args.at(0); @@ -3552,7 +4182,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_a_nullable_bool_arg = args.at(0); @@ -3593,7 +4223,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_a_nullable_int_arg = args.at(0); @@ -3631,7 +4261,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_a_nullable_double_arg = args.at(0); @@ -3669,7 +4299,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_a_nullable_bool_arg = args.at(0); @@ -3707,7 +4337,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_a_nullable_string_arg = args.at(0); @@ -3746,7 +4376,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_a_nullable_uint8_list_arg = args.at(0); @@ -3785,7 +4415,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_a_nullable_object_arg = args.at(0); @@ -3823,7 +4453,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_a_nullable_list_arg = args.at(0); @@ -3862,7 +4492,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_enum_list_arg = args.at(0); @@ -3901,7 +4531,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_class_list_arg = args.at(0); @@ -3940,7 +4570,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_enum_list_arg = args.at(0); @@ -3979,7 +4609,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_class_list_arg = args.at(0); @@ -4017,7 +4647,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_map_arg = args.at(0); @@ -4056,7 +4686,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_string_map_arg = args.at(0); @@ -4094,7 +4724,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_int_map_arg = args.at(0); @@ -4132,7 +4762,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_enum_map_arg = args.at(0); @@ -4171,7 +4801,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_class_map_arg = args.at(0); @@ -4210,7 +4840,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_string_map_arg = args.at(0); @@ -4249,7 +4879,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_int_map_arg = args.at(0); @@ -4288,7 +4918,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_enum_map_arg = args.at(0); @@ -4327,7 +4957,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_class_map_arg = args.at(0); @@ -4365,7 +4995,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_an_enum_arg = args.at(0); @@ -4409,7 +5039,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_another_enum_arg = args.at(0); @@ -4454,7 +5084,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_a_nullable_int_arg = args.at(0); @@ -4493,7 +5123,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_a_nullable_string_arg = args.at(0); @@ -4531,7 +5161,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { api->NoopAsync([reply](std::optional&& output) { if (output.has_value()) { @@ -4559,7 +5189,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_an_int_arg = args.at(0); @@ -4595,7 +5225,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_a_double_arg = args.at(0); @@ -4633,7 +5263,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_a_bool_arg = args.at(0); @@ -4669,7 +5299,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_a_string_arg = args.at(0); @@ -4707,7 +5337,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_a_uint8_list_arg = args.at(0); @@ -4746,7 +5376,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_an_object_arg = args.at(0); @@ -4783,7 +5413,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_list_arg = args.at(0); @@ -4821,7 +5451,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_enum_list_arg = args.at(0); @@ -4859,7 +5489,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_class_list_arg = args.at(0); @@ -4897,7 +5527,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_map_arg = args.at(0); @@ -4934,7 +5564,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_string_map_arg = args.at(0); @@ -4972,7 +5602,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_int_map_arg = args.at(0); @@ -5010,7 +5640,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_enum_map_arg = args.at(0); @@ -5048,7 +5678,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_class_map_arg = args.at(0); @@ -5086,7 +5716,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_an_enum_arg = args.at(0); @@ -5125,7 +5755,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_another_enum_arg = args.at(0); @@ -5163,7 +5793,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { api->ThrowAsyncError( [reply](ErrorOr>&& output) { @@ -5199,7 +5829,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { api->ThrowAsyncErrorFromVoid( [reply](std::optional&& output) { @@ -5229,7 +5859,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { api->ThrowAsyncFlutterError( [reply](ErrorOr>&& output) { @@ -5264,7 +5894,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_everything_arg = args.at(0); @@ -5303,7 +5933,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_everything_arg = args.at(0); @@ -5346,10 +5976,9 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, prepended_suffix, &GetCodec()); if (api != nullptr) { - channel.SetMessageHandler([api]( - const EncodableValue& message, - const flutter::MessageReply& - reply) { + channel.SetMessageHandler([api](const EncodableValue& message, + const ::flutter::MessageReply< + EncodableValue>& reply) { try { const auto& args = std::get(message); const auto& encodable_everything_arg = args.at(0); @@ -5395,7 +6024,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_an_int_arg = args.at(0); @@ -5436,7 +6065,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_a_double_arg = args.at(0); @@ -5477,7 +6106,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_a_bool_arg = args.at(0); @@ -5516,7 +6145,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_a_string_arg = args.at(0); @@ -5557,7 +6186,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_a_uint8_list_arg = args.at(0); @@ -5599,7 +6228,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_an_object_arg = args.at(0); @@ -5639,7 +6268,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_list_arg = args.at(0); @@ -5680,7 +6309,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_enum_list_arg = args.at(0); @@ -5721,7 +6350,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_class_list_arg = args.at(0); @@ -5762,7 +6391,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_map_arg = args.at(0); @@ -5803,7 +6432,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_string_map_arg = args.at(0); @@ -5844,7 +6473,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_int_map_arg = args.at(0); @@ -5885,7 +6514,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_enum_map_arg = args.at(0); @@ -5926,7 +6555,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_class_map_arg = args.at(0); @@ -5967,7 +6596,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_an_enum_arg = args.at(0); @@ -6013,7 +6642,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_another_enum_arg = args.at(0); @@ -6058,7 +6687,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { ErrorOr output = api->DefaultIsMainThread(); if (output.has_error()) { @@ -6086,7 +6715,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { ErrorOr output = api->TaskQueueIsBackgroundThread(); if (output.has_error()) { @@ -6113,7 +6742,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { api->CallFlutterNoop( [reply](std::optional&& output) { @@ -6143,7 +6772,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { api->CallFlutterThrowError( [reply](ErrorOr>&& output) { @@ -6179,7 +6808,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { api->CallFlutterThrowErrorFromVoid( [reply](std::optional&& output) { @@ -6209,7 +6838,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_everything_arg = args.at(0); @@ -6248,7 +6877,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_everything_arg = args.at(0); @@ -6293,7 +6922,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_a_nullable_bool_arg = args.at(0); @@ -6334,10 +6963,9 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, prepended_suffix, &GetCodec()); if (api != nullptr) { - channel.SetMessageHandler([api]( - const EncodableValue& message, - const flutter::MessageReply& - reply) { + channel.SetMessageHandler([api](const EncodableValue& message, + const ::flutter::MessageReply< + EncodableValue>& reply) { try { const auto& args = std::get(message); const auto& encodable_everything_arg = args.at(0); @@ -6383,7 +7011,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_a_nullable_bool_arg = args.at(0); @@ -6425,7 +7053,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_a_bool_arg = args.at(0); @@ -6462,7 +7090,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_an_int_arg = args.at(0); @@ -6500,7 +7128,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_a_double_arg = args.at(0); @@ -6539,7 +7167,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_a_string_arg = args.at(0); @@ -6578,7 +7206,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_list_arg = args.at(0); @@ -6616,7 +7244,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_list_arg = args.at(0); @@ -6655,7 +7283,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_enum_list_arg = args.at(0); @@ -6694,7 +7322,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_class_list_arg = args.at(0); @@ -6733,7 +7361,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_enum_list_arg = args.at(0); @@ -6772,7 +7400,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_class_list_arg = args.at(0); @@ -6810,7 +7438,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_map_arg = args.at(0); @@ -6848,7 +7476,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_string_map_arg = args.at(0); @@ -6887,7 +7515,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_int_map_arg = args.at(0); @@ -6926,7 +7554,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_enum_map_arg = args.at(0); @@ -6965,7 +7593,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_class_map_arg = args.at(0); @@ -7004,7 +7632,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_string_map_arg = args.at(0); @@ -7043,7 +7671,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_int_map_arg = args.at(0); @@ -7082,7 +7710,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_enum_map_arg = args.at(0); @@ -7121,7 +7749,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_class_map_arg = args.at(0); @@ -7159,7 +7787,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_an_enum_arg = args.at(0); @@ -7198,7 +7826,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_another_enum_arg = args.at(0); @@ -7237,7 +7865,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_a_bool_arg = args.at(0); @@ -7276,7 +7904,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_an_int_arg = args.at(0); @@ -7317,7 +7945,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_a_double_arg = args.at(0); @@ -7358,7 +7986,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_a_string_arg = args.at(0); @@ -7399,7 +8027,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_list_arg = args.at(0); @@ -7441,7 +8069,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_list_arg = args.at(0); @@ -7482,7 +8110,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_enum_list_arg = args.at(0); @@ -7523,7 +8151,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_class_list_arg = args.at(0); @@ -7564,7 +8192,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_enum_list_arg = args.at(0); @@ -7605,7 +8233,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_class_list_arg = args.at(0); @@ -7646,7 +8274,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_map_arg = args.at(0); @@ -7687,7 +8315,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_string_map_arg = args.at(0); @@ -7728,7 +8356,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_int_map_arg = args.at(0); @@ -7769,7 +8397,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_enum_map_arg = args.at(0); @@ -7810,7 +8438,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_class_map_arg = args.at(0); @@ -7851,7 +8479,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_string_map_arg = args.at(0); @@ -7892,7 +8520,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_int_map_arg = args.at(0); @@ -7933,7 +8561,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_enum_map_arg = args.at(0); @@ -7974,7 +8602,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_class_map_arg = args.at(0); @@ -8015,7 +8643,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_an_enum_arg = args.at(0); @@ -8061,7 +8689,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_another_enum_arg = args.at(0); @@ -8107,7 +8735,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_a_string_arg = args.at(0); @@ -8154,19 +8782,19 @@ EncodableValue HostIntegrationCoreApi::WrapError(const FlutterError& error) { // Generated class from Pigeon that represents Flutter messages that can be // called from C++. FlutterIntegrationCoreApi::FlutterIntegrationCoreApi( - flutter::BinaryMessenger* binary_messenger) + ::flutter::BinaryMessenger* binary_messenger) : binary_messenger_(binary_messenger), message_channel_suffix_("") {} FlutterIntegrationCoreApi::FlutterIntegrationCoreApi( - flutter::BinaryMessenger* binary_messenger, + ::flutter::BinaryMessenger* binary_messenger, const std::string& message_channel_suffix) : binary_messenger_(binary_messenger), message_channel_suffix_(message_channel_suffix.length() > 0 ? std::string(".") + message_channel_suffix : "") {} -const flutter::StandardMessageCodec& FlutterIntegrationCoreApi::GetCodec() { - return flutter::StandardMessageCodec::GetInstance( +const ::flutter::StandardMessageCodec& FlutterIntegrationCoreApi::GetCodec() { + return ::flutter::StandardMessageCodec::GetInstance( &PigeonInternalCodecSerializer::GetInstance()); } @@ -10148,19 +10776,19 @@ void FlutterIntegrationCoreApi::EchoAsyncString( } /// The codec used by HostTrivialApi. -const flutter::StandardMessageCodec& HostTrivialApi::GetCodec() { - return flutter::StandardMessageCodec::GetInstance( +const ::flutter::StandardMessageCodec& HostTrivialApi::GetCodec() { + return ::flutter::StandardMessageCodec::GetInstance( &PigeonInternalCodecSerializer::GetInstance()); } // Sets up an instance of `HostTrivialApi` to handle messages through the // `binary_messenger`. -void HostTrivialApi::SetUp(flutter::BinaryMessenger* binary_messenger, +void HostTrivialApi::SetUp(::flutter::BinaryMessenger* binary_messenger, HostTrivialApi* api) { HostTrivialApi::SetUp(binary_messenger, api, ""); } -void HostTrivialApi::SetUp(flutter::BinaryMessenger* binary_messenger, +void HostTrivialApi::SetUp(::flutter::BinaryMessenger* binary_messenger, HostTrivialApi* api, const std::string& message_channel_suffix) { const std::string prepended_suffix = @@ -10176,7 +10804,7 @@ void HostTrivialApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { std::optional output = api->Noop(); if (output.has_value()) { @@ -10209,19 +10837,19 @@ EncodableValue HostTrivialApi::WrapError(const FlutterError& error) { } /// The codec used by HostSmallApi. -const flutter::StandardMessageCodec& HostSmallApi::GetCodec() { - return flutter::StandardMessageCodec::GetInstance( +const ::flutter::StandardMessageCodec& HostSmallApi::GetCodec() { + return ::flutter::StandardMessageCodec::GetInstance( &PigeonInternalCodecSerializer::GetInstance()); } // Sets up an instance of `HostSmallApi` to handle messages through the // `binary_messenger`. -void HostSmallApi::SetUp(flutter::BinaryMessenger* binary_messenger, +void HostSmallApi::SetUp(::flutter::BinaryMessenger* binary_messenger, HostSmallApi* api) { HostSmallApi::SetUp(binary_messenger, api, ""); } -void HostSmallApi::SetUp(flutter::BinaryMessenger* binary_messenger, +void HostSmallApi::SetUp(::flutter::BinaryMessenger* binary_messenger, HostSmallApi* api, const std::string& message_channel_suffix) { const std::string prepended_suffix = @@ -10237,7 +10865,7 @@ void HostSmallApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_a_string_arg = args.at(0); @@ -10274,7 +10902,7 @@ void HostSmallApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { api->VoidVoid([reply](std::optional&& output) { if (output.has_value()) { @@ -10309,18 +10937,18 @@ EncodableValue HostSmallApi::WrapError(const FlutterError& error) { // Generated class from Pigeon that represents Flutter messages that can be // called from C++. -FlutterSmallApi::FlutterSmallApi(flutter::BinaryMessenger* binary_messenger) +FlutterSmallApi::FlutterSmallApi(::flutter::BinaryMessenger* binary_messenger) : binary_messenger_(binary_messenger), message_channel_suffix_("") {} -FlutterSmallApi::FlutterSmallApi(flutter::BinaryMessenger* binary_messenger, +FlutterSmallApi::FlutterSmallApi(::flutter::BinaryMessenger* binary_messenger, const std::string& message_channel_suffix) : binary_messenger_(binary_messenger), message_channel_suffix_(message_channel_suffix.length() > 0 ? std::string(".") + message_channel_suffix : "") {} -const flutter::StandardMessageCodec& FlutterSmallApi::GetCodec() { - return flutter::StandardMessageCodec::GetInstance( +const ::flutter::StandardMessageCodec& FlutterSmallApi::GetCodec() { + return ::flutter::StandardMessageCodec::GetInstance( &PigeonInternalCodecSerializer::GetInstance()); } diff --git a/packages/pigeon/platform_tests/test_plugin/windows/pigeon/core_tests.gen.h b/packages/pigeon/platform_tests/test_plugin/windows/pigeon/core_tests.gen.h index 450a1dfcf068..24ca4540d6a8 100644 --- a/packages/pigeon/platform_tests/test_plugin/windows/pigeon/core_tests.gen.h +++ b/packages/pigeon/platform_tests/test_plugin/windows/pigeon/core_tests.gen.h @@ -28,17 +28,17 @@ class FlutterError { explicit FlutterError(const std::string& code, const std::string& message) : code_(code), message_(message) {} explicit FlutterError(const std::string& code, const std::string& message, - const flutter::EncodableValue& details) + const ::flutter::EncodableValue& details) : code_(code), message_(message), details_(details) {} const std::string& code() const { return code_; } const std::string& message() const { return message_; } - const flutter::EncodableValue& details() const { return details_; } + const ::flutter::EncodableValue& details() const { return details_; } private: std::string code_; std::string message_; - flutter::EncodableValue details_; + ::flutter::EncodableValue details_; }; template @@ -82,15 +82,21 @@ class UnusedClass { UnusedClass(); // Constructs an object setting all fields. - explicit UnusedClass(const flutter::EncodableValue* a_field); + explicit UnusedClass(const ::flutter::EncodableValue* a_field); - const flutter::EncodableValue* a_field() const; - void set_a_field(const flutter::EncodableValue* value_arg); - void set_a_field(const flutter::EncodableValue& value_arg); + const ::flutter::EncodableValue* a_field() const; + void set_a_field(const ::flutter::EncodableValue* value_arg); + void set_a_field(const ::flutter::EncodableValue& value_arg); + + bool operator==(const UnusedClass& other) const; + bool operator!=(const UnusedClass& other) const; + /// Returns a hash code value for the object. This method is supported for the + /// benefit of hash tables. + size_t Hash() const; private: - static UnusedClass FromEncodableList(const flutter::EncodableList& list); - flutter::EncodableList ToEncodableList() const; + static UnusedClass FromEncodableList(const ::flutter::EncodableList& list); + ::flutter::EncodableList ToEncodableList() const; friend class HostIntegrationCoreApi; friend class FlutterIntegrationCoreApi; friend class HostTrivialApi; @@ -98,7 +104,7 @@ class UnusedClass { friend class FlutterSmallApi; friend class PigeonInternalCodecSerializer; friend class CoreTestsTest; - std::optional a_field_; + std::optional<::flutter::EncodableValue> a_field_; }; // A class containing all supported types. @@ -114,23 +120,23 @@ class AllTypes { const std::vector& a_float_array, const AnEnum& an_enum, const AnotherEnum& another_enum, const std::string& a_string, - const flutter::EncodableValue& an_object, - const flutter::EncodableList& list, - const flutter::EncodableList& string_list, - const flutter::EncodableList& int_list, - const flutter::EncodableList& double_list, - const flutter::EncodableList& bool_list, - const flutter::EncodableList& enum_list, - const flutter::EncodableList& object_list, - const flutter::EncodableList& list_list, - const flutter::EncodableList& map_list, - const flutter::EncodableMap& map, - const flutter::EncodableMap& string_map, - const flutter::EncodableMap& int_map, - const flutter::EncodableMap& enum_map, - const flutter::EncodableMap& object_map, - const flutter::EncodableMap& list_map, - const flutter::EncodableMap& map_map); + const ::flutter::EncodableValue& an_object, + const ::flutter::EncodableList& list, + const ::flutter::EncodableList& string_list, + const ::flutter::EncodableList& int_list, + const ::flutter::EncodableList& double_list, + const ::flutter::EncodableList& bool_list, + const ::flutter::EncodableList& enum_list, + const ::flutter::EncodableList& object_list, + const ::flutter::EncodableList& list_list, + const ::flutter::EncodableList& map_list, + const ::flutter::EncodableMap& map, + const ::flutter::EncodableMap& string_map, + const ::flutter::EncodableMap& int_map, + const ::flutter::EncodableMap& enum_map, + const ::flutter::EncodableMap& object_map, + const ::flutter::EncodableMap& list_map, + const ::flutter::EncodableMap& map_map); bool a_bool() const; void set_a_bool(bool value_arg); @@ -165,60 +171,66 @@ class AllTypes { const std::string& a_string() const; void set_a_string(std::string_view value_arg); - const flutter::EncodableValue& an_object() const; - void set_an_object(const flutter::EncodableValue& value_arg); + const ::flutter::EncodableValue& an_object() const; + void set_an_object(const ::flutter::EncodableValue& value_arg); + + const ::flutter::EncodableList& list() const; + void set_list(const ::flutter::EncodableList& value_arg); - const flutter::EncodableList& list() const; - void set_list(const flutter::EncodableList& value_arg); + const ::flutter::EncodableList& string_list() const; + void set_string_list(const ::flutter::EncodableList& value_arg); - const flutter::EncodableList& string_list() const; - void set_string_list(const flutter::EncodableList& value_arg); + const ::flutter::EncodableList& int_list() const; + void set_int_list(const ::flutter::EncodableList& value_arg); - const flutter::EncodableList& int_list() const; - void set_int_list(const flutter::EncodableList& value_arg); + const ::flutter::EncodableList& double_list() const; + void set_double_list(const ::flutter::EncodableList& value_arg); - const flutter::EncodableList& double_list() const; - void set_double_list(const flutter::EncodableList& value_arg); + const ::flutter::EncodableList& bool_list() const; + void set_bool_list(const ::flutter::EncodableList& value_arg); - const flutter::EncodableList& bool_list() const; - void set_bool_list(const flutter::EncodableList& value_arg); + const ::flutter::EncodableList& enum_list() const; + void set_enum_list(const ::flutter::EncodableList& value_arg); - const flutter::EncodableList& enum_list() const; - void set_enum_list(const flutter::EncodableList& value_arg); + const ::flutter::EncodableList& object_list() const; + void set_object_list(const ::flutter::EncodableList& value_arg); - const flutter::EncodableList& object_list() const; - void set_object_list(const flutter::EncodableList& value_arg); + const ::flutter::EncodableList& list_list() const; + void set_list_list(const ::flutter::EncodableList& value_arg); - const flutter::EncodableList& list_list() const; - void set_list_list(const flutter::EncodableList& value_arg); + const ::flutter::EncodableList& map_list() const; + void set_map_list(const ::flutter::EncodableList& value_arg); - const flutter::EncodableList& map_list() const; - void set_map_list(const flutter::EncodableList& value_arg); + const ::flutter::EncodableMap& map() const; + void set_map(const ::flutter::EncodableMap& value_arg); - const flutter::EncodableMap& map() const; - void set_map(const flutter::EncodableMap& value_arg); + const ::flutter::EncodableMap& string_map() const; + void set_string_map(const ::flutter::EncodableMap& value_arg); - const flutter::EncodableMap& string_map() const; - void set_string_map(const flutter::EncodableMap& value_arg); + const ::flutter::EncodableMap& int_map() const; + void set_int_map(const ::flutter::EncodableMap& value_arg); - const flutter::EncodableMap& int_map() const; - void set_int_map(const flutter::EncodableMap& value_arg); + const ::flutter::EncodableMap& enum_map() const; + void set_enum_map(const ::flutter::EncodableMap& value_arg); - const flutter::EncodableMap& enum_map() const; - void set_enum_map(const flutter::EncodableMap& value_arg); + const ::flutter::EncodableMap& object_map() const; + void set_object_map(const ::flutter::EncodableMap& value_arg); - const flutter::EncodableMap& object_map() const; - void set_object_map(const flutter::EncodableMap& value_arg); + const ::flutter::EncodableMap& list_map() const; + void set_list_map(const ::flutter::EncodableMap& value_arg); - const flutter::EncodableMap& list_map() const; - void set_list_map(const flutter::EncodableMap& value_arg); + const ::flutter::EncodableMap& map_map() const; + void set_map_map(const ::flutter::EncodableMap& value_arg); - const flutter::EncodableMap& map_map() const; - void set_map_map(const flutter::EncodableMap& value_arg); + bool operator==(const AllTypes& other) const; + bool operator!=(const AllTypes& other) const; + /// Returns a hash code value for the object. This method is supported for the + /// benefit of hash tables. + size_t Hash() const; private: - static AllTypes FromEncodableList(const flutter::EncodableList& list); - flutter::EncodableList ToEncodableList() const; + static AllTypes FromEncodableList(const ::flutter::EncodableList& list); + ::flutter::EncodableList ToEncodableList() const; friend class AllClassesWrapper; friend class HostIntegrationCoreApi; friend class FlutterIntegrationCoreApi; @@ -238,23 +250,23 @@ class AllTypes { AnEnum an_enum_; AnotherEnum another_enum_; std::string a_string_; - flutter::EncodableValue an_object_; - flutter::EncodableList list_; - flutter::EncodableList string_list_; - flutter::EncodableList int_list_; - flutter::EncodableList double_list_; - flutter::EncodableList bool_list_; - flutter::EncodableList enum_list_; - flutter::EncodableList object_list_; - flutter::EncodableList list_list_; - flutter::EncodableList map_list_; - flutter::EncodableMap map_; - flutter::EncodableMap string_map_; - flutter::EncodableMap int_map_; - flutter::EncodableMap enum_map_; - flutter::EncodableMap object_map_; - flutter::EncodableMap list_map_; - flutter::EncodableMap map_map_; + ::flutter::EncodableValue an_object_; + ::flutter::EncodableList list_; + ::flutter::EncodableList string_list_; + ::flutter::EncodableList int_list_; + ::flutter::EncodableList double_list_; + ::flutter::EncodableList bool_list_; + ::flutter::EncodableList enum_list_; + ::flutter::EncodableList object_list_; + ::flutter::EncodableList list_list_; + ::flutter::EncodableList map_list_; + ::flutter::EncodableMap map_; + ::flutter::EncodableMap string_map_; + ::flutter::EncodableMap int_map_; + ::flutter::EncodableMap enum_map_; + ::flutter::EncodableMap object_map_; + ::flutter::EncodableMap list_map_; + ::flutter::EncodableMap map_map_; }; // A class containing all supported nullable types. @@ -275,25 +287,26 @@ class AllNullableTypes { const std::vector* a_nullable_float_array, const AnEnum* a_nullable_enum, const AnotherEnum* another_nullable_enum, const std::string* a_nullable_string, - const flutter::EncodableValue* a_nullable_object, + const ::flutter::EncodableValue* a_nullable_object, const AllNullableTypes* all_nullable_types, - const flutter::EncodableList* list, - const flutter::EncodableList* string_list, - const flutter::EncodableList* int_list, - const flutter::EncodableList* double_list, - const flutter::EncodableList* bool_list, - const flutter::EncodableList* enum_list, - const flutter::EncodableList* object_list, - const flutter::EncodableList* list_list, - const flutter::EncodableList* map_list, - const flutter::EncodableList* recursive_class_list, - const flutter::EncodableMap* map, const flutter::EncodableMap* string_map, - const flutter::EncodableMap* int_map, - const flutter::EncodableMap* enum_map, - const flutter::EncodableMap* object_map, - const flutter::EncodableMap* list_map, - const flutter::EncodableMap* map_map, - const flutter::EncodableMap* recursive_class_map); + const ::flutter::EncodableList* list, + const ::flutter::EncodableList* string_list, + const ::flutter::EncodableList* int_list, + const ::flutter::EncodableList* double_list, + const ::flutter::EncodableList* bool_list, + const ::flutter::EncodableList* enum_list, + const ::flutter::EncodableList* object_list, + const ::flutter::EncodableList* list_list, + const ::flutter::EncodableList* map_list, + const ::flutter::EncodableList* recursive_class_list, + const ::flutter::EncodableMap* map, + const ::flutter::EncodableMap* string_map, + const ::flutter::EncodableMap* int_map, + const ::flutter::EncodableMap* enum_map, + const ::flutter::EncodableMap* object_map, + const ::flutter::EncodableMap* list_map, + const ::flutter::EncodableMap* map_map, + const ::flutter::EncodableMap* recursive_class_map); ~AllNullableTypes() = default; AllNullableTypes(const AllNullableTypes& other); @@ -344,89 +357,96 @@ class AllNullableTypes { void set_a_nullable_string(const std::string_view* value_arg); void set_a_nullable_string(std::string_view value_arg); - const flutter::EncodableValue* a_nullable_object() const; - void set_a_nullable_object(const flutter::EncodableValue* value_arg); - void set_a_nullable_object(const flutter::EncodableValue& value_arg); + const ::flutter::EncodableValue* a_nullable_object() const; + void set_a_nullable_object(const ::flutter::EncodableValue* value_arg); + void set_a_nullable_object(const ::flutter::EncodableValue& value_arg); const AllNullableTypes* all_nullable_types() const; void set_all_nullable_types(const AllNullableTypes* value_arg); void set_all_nullable_types(const AllNullableTypes& value_arg); - const flutter::EncodableList* list() const; - void set_list(const flutter::EncodableList* value_arg); - void set_list(const flutter::EncodableList& value_arg); + const ::flutter::EncodableList* list() const; + void set_list(const ::flutter::EncodableList* value_arg); + void set_list(const ::flutter::EncodableList& value_arg); + + const ::flutter::EncodableList* string_list() const; + void set_string_list(const ::flutter::EncodableList* value_arg); + void set_string_list(const ::flutter::EncodableList& value_arg); - const flutter::EncodableList* string_list() const; - void set_string_list(const flutter::EncodableList* value_arg); - void set_string_list(const flutter::EncodableList& value_arg); + const ::flutter::EncodableList* int_list() const; + void set_int_list(const ::flutter::EncodableList* value_arg); + void set_int_list(const ::flutter::EncodableList& value_arg); - const flutter::EncodableList* int_list() const; - void set_int_list(const flutter::EncodableList* value_arg); - void set_int_list(const flutter::EncodableList& value_arg); + const ::flutter::EncodableList* double_list() const; + void set_double_list(const ::flutter::EncodableList* value_arg); + void set_double_list(const ::flutter::EncodableList& value_arg); - const flutter::EncodableList* double_list() const; - void set_double_list(const flutter::EncodableList* value_arg); - void set_double_list(const flutter::EncodableList& value_arg); + const ::flutter::EncodableList* bool_list() const; + void set_bool_list(const ::flutter::EncodableList* value_arg); + void set_bool_list(const ::flutter::EncodableList& value_arg); - const flutter::EncodableList* bool_list() const; - void set_bool_list(const flutter::EncodableList* value_arg); - void set_bool_list(const flutter::EncodableList& value_arg); + const ::flutter::EncodableList* enum_list() const; + void set_enum_list(const ::flutter::EncodableList* value_arg); + void set_enum_list(const ::flutter::EncodableList& value_arg); - const flutter::EncodableList* enum_list() const; - void set_enum_list(const flutter::EncodableList* value_arg); - void set_enum_list(const flutter::EncodableList& value_arg); + const ::flutter::EncodableList* object_list() const; + void set_object_list(const ::flutter::EncodableList* value_arg); + void set_object_list(const ::flutter::EncodableList& value_arg); - const flutter::EncodableList* object_list() const; - void set_object_list(const flutter::EncodableList* value_arg); - void set_object_list(const flutter::EncodableList& value_arg); + const ::flutter::EncodableList* list_list() const; + void set_list_list(const ::flutter::EncodableList* value_arg); + void set_list_list(const ::flutter::EncodableList& value_arg); - const flutter::EncodableList* list_list() const; - void set_list_list(const flutter::EncodableList* value_arg); - void set_list_list(const flutter::EncodableList& value_arg); + const ::flutter::EncodableList* map_list() const; + void set_map_list(const ::flutter::EncodableList* value_arg); + void set_map_list(const ::flutter::EncodableList& value_arg); - const flutter::EncodableList* map_list() const; - void set_map_list(const flutter::EncodableList* value_arg); - void set_map_list(const flutter::EncodableList& value_arg); + const ::flutter::EncodableList* recursive_class_list() const; + void set_recursive_class_list(const ::flutter::EncodableList* value_arg); + void set_recursive_class_list(const ::flutter::EncodableList& value_arg); - const flutter::EncodableList* recursive_class_list() const; - void set_recursive_class_list(const flutter::EncodableList* value_arg); - void set_recursive_class_list(const flutter::EncodableList& value_arg); + const ::flutter::EncodableMap* map() const; + void set_map(const ::flutter::EncodableMap* value_arg); + void set_map(const ::flutter::EncodableMap& value_arg); - const flutter::EncodableMap* map() const; - void set_map(const flutter::EncodableMap* value_arg); - void set_map(const flutter::EncodableMap& value_arg); + const ::flutter::EncodableMap* string_map() const; + void set_string_map(const ::flutter::EncodableMap* value_arg); + void set_string_map(const ::flutter::EncodableMap& value_arg); - const flutter::EncodableMap* string_map() const; - void set_string_map(const flutter::EncodableMap* value_arg); - void set_string_map(const flutter::EncodableMap& value_arg); + const ::flutter::EncodableMap* int_map() const; + void set_int_map(const ::flutter::EncodableMap* value_arg); + void set_int_map(const ::flutter::EncodableMap& value_arg); - const flutter::EncodableMap* int_map() const; - void set_int_map(const flutter::EncodableMap* value_arg); - void set_int_map(const flutter::EncodableMap& value_arg); + const ::flutter::EncodableMap* enum_map() const; + void set_enum_map(const ::flutter::EncodableMap* value_arg); + void set_enum_map(const ::flutter::EncodableMap& value_arg); - const flutter::EncodableMap* enum_map() const; - void set_enum_map(const flutter::EncodableMap* value_arg); - void set_enum_map(const flutter::EncodableMap& value_arg); + const ::flutter::EncodableMap* object_map() const; + void set_object_map(const ::flutter::EncodableMap* value_arg); + void set_object_map(const ::flutter::EncodableMap& value_arg); - const flutter::EncodableMap* object_map() const; - void set_object_map(const flutter::EncodableMap* value_arg); - void set_object_map(const flutter::EncodableMap& value_arg); + const ::flutter::EncodableMap* list_map() const; + void set_list_map(const ::flutter::EncodableMap* value_arg); + void set_list_map(const ::flutter::EncodableMap& value_arg); - const flutter::EncodableMap* list_map() const; - void set_list_map(const flutter::EncodableMap* value_arg); - void set_list_map(const flutter::EncodableMap& value_arg); + const ::flutter::EncodableMap* map_map() const; + void set_map_map(const ::flutter::EncodableMap* value_arg); + void set_map_map(const ::flutter::EncodableMap& value_arg); - const flutter::EncodableMap* map_map() const; - void set_map_map(const flutter::EncodableMap* value_arg); - void set_map_map(const flutter::EncodableMap& value_arg); + const ::flutter::EncodableMap* recursive_class_map() const; + void set_recursive_class_map(const ::flutter::EncodableMap* value_arg); + void set_recursive_class_map(const ::flutter::EncodableMap& value_arg); - const flutter::EncodableMap* recursive_class_map() const; - void set_recursive_class_map(const flutter::EncodableMap* value_arg); - void set_recursive_class_map(const flutter::EncodableMap& value_arg); + bool operator==(const AllNullableTypes& other) const; + bool operator!=(const AllNullableTypes& other) const; + /// Returns a hash code value for the object. This method is supported for the + /// benefit of hash tables. + size_t Hash() const; private: - static AllNullableTypes FromEncodableList(const flutter::EncodableList& list); - flutter::EncodableList ToEncodableList() const; + static AllNullableTypes FromEncodableList( + const ::flutter::EncodableList& list); + ::flutter::EncodableList ToEncodableList() const; friend class AllClassesWrapper; friend class HostIntegrationCoreApi; friend class FlutterIntegrationCoreApi; @@ -446,26 +466,26 @@ class AllNullableTypes { std::optional a_nullable_enum_; std::optional another_nullable_enum_; std::optional a_nullable_string_; - std::optional a_nullable_object_; + std::optional<::flutter::EncodableValue> a_nullable_object_; std::unique_ptr all_nullable_types_; - std::optional list_; - std::optional string_list_; - std::optional int_list_; - std::optional double_list_; - std::optional bool_list_; - std::optional enum_list_; - std::optional object_list_; - std::optional list_list_; - std::optional map_list_; - std::optional recursive_class_list_; - std::optional map_; - std::optional string_map_; - std::optional int_map_; - std::optional enum_map_; - std::optional object_map_; - std::optional list_map_; - std::optional map_map_; - std::optional recursive_class_map_; + std::optional<::flutter::EncodableList> list_; + std::optional<::flutter::EncodableList> string_list_; + std::optional<::flutter::EncodableList> int_list_; + std::optional<::flutter::EncodableList> double_list_; + std::optional<::flutter::EncodableList> bool_list_; + std::optional<::flutter::EncodableList> enum_list_; + std::optional<::flutter::EncodableList> object_list_; + std::optional<::flutter::EncodableList> list_list_; + std::optional<::flutter::EncodableList> map_list_; + std::optional<::flutter::EncodableList> recursive_class_list_; + std::optional<::flutter::EncodableMap> map_; + std::optional<::flutter::EncodableMap> string_map_; + std::optional<::flutter::EncodableMap> int_map_; + std::optional<::flutter::EncodableMap> enum_map_; + std::optional<::flutter::EncodableMap> object_map_; + std::optional<::flutter::EncodableMap> list_map_; + std::optional<::flutter::EncodableMap> map_map_; + std::optional<::flutter::EncodableMap> recursive_class_map_; }; // The primary purpose for this class is to ensure coverage of Swift structs @@ -488,22 +508,23 @@ class AllNullableTypesWithoutRecursion { const std::vector* a_nullable_float_array, const AnEnum* a_nullable_enum, const AnotherEnum* another_nullable_enum, const std::string* a_nullable_string, - const flutter::EncodableValue* a_nullable_object, - const flutter::EncodableList* list, - const flutter::EncodableList* string_list, - const flutter::EncodableList* int_list, - const flutter::EncodableList* double_list, - const flutter::EncodableList* bool_list, - const flutter::EncodableList* enum_list, - const flutter::EncodableList* object_list, - const flutter::EncodableList* list_list, - const flutter::EncodableList* map_list, const flutter::EncodableMap* map, - const flutter::EncodableMap* string_map, - const flutter::EncodableMap* int_map, - const flutter::EncodableMap* enum_map, - const flutter::EncodableMap* object_map, - const flutter::EncodableMap* list_map, - const flutter::EncodableMap* map_map); + const ::flutter::EncodableValue* a_nullable_object, + const ::flutter::EncodableList* list, + const ::flutter::EncodableList* string_list, + const ::flutter::EncodableList* int_list, + const ::flutter::EncodableList* double_list, + const ::flutter::EncodableList* bool_list, + const ::flutter::EncodableList* enum_list, + const ::flutter::EncodableList* object_list, + const ::flutter::EncodableList* list_list, + const ::flutter::EncodableList* map_list, + const ::flutter::EncodableMap* map, + const ::flutter::EncodableMap* string_map, + const ::flutter::EncodableMap* int_map, + const ::flutter::EncodableMap* enum_map, + const ::flutter::EncodableMap* object_map, + const ::flutter::EncodableMap* list_map, + const ::flutter::EncodableMap* map_map); const bool* a_nullable_bool() const; void set_a_nullable_bool(const bool* value_arg); @@ -549,78 +570,84 @@ class AllNullableTypesWithoutRecursion { void set_a_nullable_string(const std::string_view* value_arg); void set_a_nullable_string(std::string_view value_arg); - const flutter::EncodableValue* a_nullable_object() const; - void set_a_nullable_object(const flutter::EncodableValue* value_arg); - void set_a_nullable_object(const flutter::EncodableValue& value_arg); + const ::flutter::EncodableValue* a_nullable_object() const; + void set_a_nullable_object(const ::flutter::EncodableValue* value_arg); + void set_a_nullable_object(const ::flutter::EncodableValue& value_arg); - const flutter::EncodableList* list() const; - void set_list(const flutter::EncodableList* value_arg); - void set_list(const flutter::EncodableList& value_arg); + const ::flutter::EncodableList* list() const; + void set_list(const ::flutter::EncodableList* value_arg); + void set_list(const ::flutter::EncodableList& value_arg); - const flutter::EncodableList* string_list() const; - void set_string_list(const flutter::EncodableList* value_arg); - void set_string_list(const flutter::EncodableList& value_arg); + const ::flutter::EncodableList* string_list() const; + void set_string_list(const ::flutter::EncodableList* value_arg); + void set_string_list(const ::flutter::EncodableList& value_arg); - const flutter::EncodableList* int_list() const; - void set_int_list(const flutter::EncodableList* value_arg); - void set_int_list(const flutter::EncodableList& value_arg); + const ::flutter::EncodableList* int_list() const; + void set_int_list(const ::flutter::EncodableList* value_arg); + void set_int_list(const ::flutter::EncodableList& value_arg); - const flutter::EncodableList* double_list() const; - void set_double_list(const flutter::EncodableList* value_arg); - void set_double_list(const flutter::EncodableList& value_arg); + const ::flutter::EncodableList* double_list() const; + void set_double_list(const ::flutter::EncodableList* value_arg); + void set_double_list(const ::flutter::EncodableList& value_arg); - const flutter::EncodableList* bool_list() const; - void set_bool_list(const flutter::EncodableList* value_arg); - void set_bool_list(const flutter::EncodableList& value_arg); + const ::flutter::EncodableList* bool_list() const; + void set_bool_list(const ::flutter::EncodableList* value_arg); + void set_bool_list(const ::flutter::EncodableList& value_arg); - const flutter::EncodableList* enum_list() const; - void set_enum_list(const flutter::EncodableList* value_arg); - void set_enum_list(const flutter::EncodableList& value_arg); + const ::flutter::EncodableList* enum_list() const; + void set_enum_list(const ::flutter::EncodableList* value_arg); + void set_enum_list(const ::flutter::EncodableList& value_arg); - const flutter::EncodableList* object_list() const; - void set_object_list(const flutter::EncodableList* value_arg); - void set_object_list(const flutter::EncodableList& value_arg); + const ::flutter::EncodableList* object_list() const; + void set_object_list(const ::flutter::EncodableList* value_arg); + void set_object_list(const ::flutter::EncodableList& value_arg); - const flutter::EncodableList* list_list() const; - void set_list_list(const flutter::EncodableList* value_arg); - void set_list_list(const flutter::EncodableList& value_arg); + const ::flutter::EncodableList* list_list() const; + void set_list_list(const ::flutter::EncodableList* value_arg); + void set_list_list(const ::flutter::EncodableList& value_arg); - const flutter::EncodableList* map_list() const; - void set_map_list(const flutter::EncodableList* value_arg); - void set_map_list(const flutter::EncodableList& value_arg); + const ::flutter::EncodableList* map_list() const; + void set_map_list(const ::flutter::EncodableList* value_arg); + void set_map_list(const ::flutter::EncodableList& value_arg); - const flutter::EncodableMap* map() const; - void set_map(const flutter::EncodableMap* value_arg); - void set_map(const flutter::EncodableMap& value_arg); + const ::flutter::EncodableMap* map() const; + void set_map(const ::flutter::EncodableMap* value_arg); + void set_map(const ::flutter::EncodableMap& value_arg); - const flutter::EncodableMap* string_map() const; - void set_string_map(const flutter::EncodableMap* value_arg); - void set_string_map(const flutter::EncodableMap& value_arg); + const ::flutter::EncodableMap* string_map() const; + void set_string_map(const ::flutter::EncodableMap* value_arg); + void set_string_map(const ::flutter::EncodableMap& value_arg); - const flutter::EncodableMap* int_map() const; - void set_int_map(const flutter::EncodableMap* value_arg); - void set_int_map(const flutter::EncodableMap& value_arg); + const ::flutter::EncodableMap* int_map() const; + void set_int_map(const ::flutter::EncodableMap* value_arg); + void set_int_map(const ::flutter::EncodableMap& value_arg); - const flutter::EncodableMap* enum_map() const; - void set_enum_map(const flutter::EncodableMap* value_arg); - void set_enum_map(const flutter::EncodableMap& value_arg); + const ::flutter::EncodableMap* enum_map() const; + void set_enum_map(const ::flutter::EncodableMap* value_arg); + void set_enum_map(const ::flutter::EncodableMap& value_arg); - const flutter::EncodableMap* object_map() const; - void set_object_map(const flutter::EncodableMap* value_arg); - void set_object_map(const flutter::EncodableMap& value_arg); + const ::flutter::EncodableMap* object_map() const; + void set_object_map(const ::flutter::EncodableMap* value_arg); + void set_object_map(const ::flutter::EncodableMap& value_arg); - const flutter::EncodableMap* list_map() const; - void set_list_map(const flutter::EncodableMap* value_arg); - void set_list_map(const flutter::EncodableMap& value_arg); + const ::flutter::EncodableMap* list_map() const; + void set_list_map(const ::flutter::EncodableMap* value_arg); + void set_list_map(const ::flutter::EncodableMap& value_arg); - const flutter::EncodableMap* map_map() const; - void set_map_map(const flutter::EncodableMap* value_arg); - void set_map_map(const flutter::EncodableMap& value_arg); + const ::flutter::EncodableMap* map_map() const; + void set_map_map(const ::flutter::EncodableMap* value_arg); + void set_map_map(const ::flutter::EncodableMap& value_arg); + + bool operator==(const AllNullableTypesWithoutRecursion& other) const; + bool operator!=(const AllNullableTypesWithoutRecursion& other) const; + /// Returns a hash code value for the object. This method is supported for the + /// benefit of hash tables. + size_t Hash() const; private: static AllNullableTypesWithoutRecursion FromEncodableList( - const flutter::EncodableList& list); - flutter::EncodableList ToEncodableList() const; + const ::flutter::EncodableList& list); + ::flutter::EncodableList ToEncodableList() const; friend class AllClassesWrapper; friend class HostIntegrationCoreApi; friend class FlutterIntegrationCoreApi; @@ -640,23 +667,23 @@ class AllNullableTypesWithoutRecursion { std::optional a_nullable_enum_; std::optional another_nullable_enum_; std::optional a_nullable_string_; - std::optional a_nullable_object_; - std::optional list_; - std::optional string_list_; - std::optional int_list_; - std::optional double_list_; - std::optional bool_list_; - std::optional enum_list_; - std::optional object_list_; - std::optional list_list_; - std::optional map_list_; - std::optional map_; - std::optional string_map_; - std::optional int_map_; - std::optional enum_map_; - std::optional object_map_; - std::optional list_map_; - std::optional map_map_; + std::optional<::flutter::EncodableValue> a_nullable_object_; + std::optional<::flutter::EncodableList> list_; + std::optional<::flutter::EncodableList> string_list_; + std::optional<::flutter::EncodableList> int_list_; + std::optional<::flutter::EncodableList> double_list_; + std::optional<::flutter::EncodableList> bool_list_; + std::optional<::flutter::EncodableList> enum_list_; + std::optional<::flutter::EncodableList> object_list_; + std::optional<::flutter::EncodableList> list_list_; + std::optional<::flutter::EncodableList> map_list_; + std::optional<::flutter::EncodableMap> map_; + std::optional<::flutter::EncodableMap> string_map_; + std::optional<::flutter::EncodableMap> int_map_; + std::optional<::flutter::EncodableMap> enum_map_; + std::optional<::flutter::EncodableMap> object_map_; + std::optional<::flutter::EncodableMap> list_map_; + std::optional<::flutter::EncodableMap> map_map_; }; // A class for testing nested class handling. @@ -670,18 +697,18 @@ class AllClassesWrapper { public: // Constructs an object setting all non-nullable fields. explicit AllClassesWrapper(const AllNullableTypes& all_nullable_types, - const flutter::EncodableList& class_list, - const flutter::EncodableMap& class_map); + const ::flutter::EncodableList& class_list, + const ::flutter::EncodableMap& class_map); // Constructs an object setting all fields. - explicit AllClassesWrapper(const AllNullableTypes& all_nullable_types, - const AllNullableTypesWithoutRecursion* - all_nullable_types_without_recursion, - const AllTypes* all_types, - const flutter::EncodableList& class_list, - const flutter::EncodableList* nullable_class_list, - const flutter::EncodableMap& class_map, - const flutter::EncodableMap* nullable_class_map); + explicit AllClassesWrapper( + const AllNullableTypes& all_nullable_types, + const AllNullableTypesWithoutRecursion* + all_nullable_types_without_recursion, + const AllTypes* all_types, const ::flutter::EncodableList& class_list, + const ::flutter::EncodableList* nullable_class_list, + const ::flutter::EncodableMap& class_map, + const ::flutter::EncodableMap* nullable_class_map); ~AllClassesWrapper() = default; AllClassesWrapper(const AllClassesWrapper& other); @@ -702,24 +729,30 @@ class AllClassesWrapper { void set_all_types(const AllTypes* value_arg); void set_all_types(const AllTypes& value_arg); - const flutter::EncodableList& class_list() const; - void set_class_list(const flutter::EncodableList& value_arg); + const ::flutter::EncodableList& class_list() const; + void set_class_list(const ::flutter::EncodableList& value_arg); + + const ::flutter::EncodableList* nullable_class_list() const; + void set_nullable_class_list(const ::flutter::EncodableList* value_arg); + void set_nullable_class_list(const ::flutter::EncodableList& value_arg); - const flutter::EncodableList* nullable_class_list() const; - void set_nullable_class_list(const flutter::EncodableList* value_arg); - void set_nullable_class_list(const flutter::EncodableList& value_arg); + const ::flutter::EncodableMap& class_map() const; + void set_class_map(const ::flutter::EncodableMap& value_arg); - const flutter::EncodableMap& class_map() const; - void set_class_map(const flutter::EncodableMap& value_arg); + const ::flutter::EncodableMap* nullable_class_map() const; + void set_nullable_class_map(const ::flutter::EncodableMap* value_arg); + void set_nullable_class_map(const ::flutter::EncodableMap& value_arg); - const flutter::EncodableMap* nullable_class_map() const; - void set_nullable_class_map(const flutter::EncodableMap* value_arg); - void set_nullable_class_map(const flutter::EncodableMap& value_arg); + bool operator==(const AllClassesWrapper& other) const; + bool operator!=(const AllClassesWrapper& other) const; + /// Returns a hash code value for the object. This method is supported for the + /// benefit of hash tables. + size_t Hash() const; private: static AllClassesWrapper FromEncodableList( - const flutter::EncodableList& list); - flutter::EncodableList ToEncodableList() const; + const ::flutter::EncodableList& list); + ::flutter::EncodableList ToEncodableList() const; friend class HostIntegrationCoreApi; friend class FlutterIntegrationCoreApi; friend class HostTrivialApi; @@ -731,10 +764,10 @@ class AllClassesWrapper { std::unique_ptr all_nullable_types_without_recursion_; std::unique_ptr all_types_; - flutter::EncodableList class_list_; - std::optional nullable_class_list_; - flutter::EncodableMap class_map_; - std::optional nullable_class_map_; + ::flutter::EncodableList class_list_; + std::optional<::flutter::EncodableList> nullable_class_list_; + ::flutter::EncodableMap class_map_; + std::optional<::flutter::EncodableMap> nullable_class_map_; }; // A data class containing a List, used in unit tests. @@ -746,15 +779,21 @@ class TestMessage { TestMessage(); // Constructs an object setting all fields. - explicit TestMessage(const flutter::EncodableList* test_list); + explicit TestMessage(const ::flutter::EncodableList* test_list); - const flutter::EncodableList* test_list() const; - void set_test_list(const flutter::EncodableList* value_arg); - void set_test_list(const flutter::EncodableList& value_arg); + const ::flutter::EncodableList* test_list() const; + void set_test_list(const ::flutter::EncodableList* value_arg); + void set_test_list(const ::flutter::EncodableList& value_arg); + + bool operator==(const TestMessage& other) const; + bool operator!=(const TestMessage& other) const; + /// Returns a hash code value for the object. This method is supported for the + /// benefit of hash tables. + size_t Hash() const; private: - static TestMessage FromEncodableList(const flutter::EncodableList& list); - flutter::EncodableList ToEncodableList() const; + static TestMessage FromEncodableList(const ::flutter::EncodableList& list); + ::flutter::EncodableList ToEncodableList() const; friend class HostIntegrationCoreApi; friend class FlutterIntegrationCoreApi; friend class HostTrivialApi; @@ -762,10 +801,11 @@ class TestMessage { friend class FlutterSmallApi; friend class PigeonInternalCodecSerializer; friend class CoreTestsTest; - std::optional test_list_; + std::optional<::flutter::EncodableList> test_list_; }; -class PigeonInternalCodecSerializer : public flutter::StandardCodecSerializer { +class PigeonInternalCodecSerializer + : public ::flutter::StandardCodecSerializer { public: PigeonInternalCodecSerializer(); inline static PigeonInternalCodecSerializer& GetInstance() { @@ -773,12 +813,12 @@ class PigeonInternalCodecSerializer : public flutter::StandardCodecSerializer { return sInstance; } - void WriteValue(const flutter::EncodableValue& value, - flutter::ByteStreamWriter* stream) const override; + void WriteValue(const ::flutter::EncodableValue& value, + ::flutter::ByteStreamWriter* stream) const override; protected: - flutter::EncodableValue ReadValueOfType( - uint8_t type, flutter::ByteStreamReader* stream) const override; + ::flutter::EncodableValue ReadValueOfType( + uint8_t type, ::flutter::ByteStreamReader* stream) const override; }; // The core interface that each host language plugin must implement in @@ -797,11 +837,11 @@ class HostIntegrationCoreApi { // Returns the passed object, to test serialization and deserialization. virtual ErrorOr EchoAllTypes(const AllTypes& everything) = 0; // Returns an error, to test error handling. - virtual ErrorOr> ThrowError() = 0; + virtual ErrorOr> ThrowError() = 0; // Returns an error from a void function, to test error handling. virtual std::optional ThrowErrorFromVoid() = 0; // Returns a Flutter error, to test error handling. - virtual ErrorOr> + virtual ErrorOr> ThrowFlutterError() = 0; // Returns passed in int. virtual ErrorOr EchoInt(int64_t an_int) = 0; @@ -815,50 +855,50 @@ class HostIntegrationCoreApi { virtual ErrorOr> EchoUint8List( const std::vector& a_uint8_list) = 0; // Returns the passed in generic Object. - virtual ErrorOr EchoObject( - const flutter::EncodableValue& an_object) = 0; + virtual ErrorOr<::flutter::EncodableValue> EchoObject( + const ::flutter::EncodableValue& an_object) = 0; // Returns the passed list, to test serialization and deserialization. - virtual ErrorOr EchoList( - const flutter::EncodableList& list) = 0; + virtual ErrorOr<::flutter::EncodableList> EchoList( + const ::flutter::EncodableList& list) = 0; // Returns the passed list, to test serialization and deserialization. - virtual ErrorOr EchoEnumList( - const flutter::EncodableList& enum_list) = 0; + virtual ErrorOr<::flutter::EncodableList> EchoEnumList( + const ::flutter::EncodableList& enum_list) = 0; // Returns the passed list, to test serialization and deserialization. - virtual ErrorOr EchoClassList( - const flutter::EncodableList& class_list) = 0; + virtual ErrorOr<::flutter::EncodableList> EchoClassList( + const ::flutter::EncodableList& class_list) = 0; // Returns the passed list, to test serialization and deserialization. - virtual ErrorOr EchoNonNullEnumList( - const flutter::EncodableList& enum_list) = 0; + virtual ErrorOr<::flutter::EncodableList> EchoNonNullEnumList( + const ::flutter::EncodableList& enum_list) = 0; // Returns the passed list, to test serialization and deserialization. - virtual ErrorOr EchoNonNullClassList( - const flutter::EncodableList& class_list) = 0; + virtual ErrorOr<::flutter::EncodableList> EchoNonNullClassList( + const ::flutter::EncodableList& class_list) = 0; // Returns the passed map, to test serialization and deserialization. - virtual ErrorOr EchoMap( - const flutter::EncodableMap& map) = 0; + virtual ErrorOr<::flutter::EncodableMap> EchoMap( + const ::flutter::EncodableMap& map) = 0; // Returns the passed map, to test serialization and deserialization. - virtual ErrorOr EchoStringMap( - const flutter::EncodableMap& string_map) = 0; + virtual ErrorOr<::flutter::EncodableMap> EchoStringMap( + const ::flutter::EncodableMap& string_map) = 0; // Returns the passed map, to test serialization and deserialization. - virtual ErrorOr EchoIntMap( - const flutter::EncodableMap& int_map) = 0; + virtual ErrorOr<::flutter::EncodableMap> EchoIntMap( + const ::flutter::EncodableMap& int_map) = 0; // Returns the passed map, to test serialization and deserialization. - virtual ErrorOr EchoEnumMap( - const flutter::EncodableMap& enum_map) = 0; + virtual ErrorOr<::flutter::EncodableMap> EchoEnumMap( + const ::flutter::EncodableMap& enum_map) = 0; // Returns the passed map, to test serialization and deserialization. - virtual ErrorOr EchoClassMap( - const flutter::EncodableMap& class_map) = 0; + virtual ErrorOr<::flutter::EncodableMap> EchoClassMap( + const ::flutter::EncodableMap& class_map) = 0; // Returns the passed map, to test serialization and deserialization. - virtual ErrorOr EchoNonNullStringMap( - const flutter::EncodableMap& string_map) = 0; + virtual ErrorOr<::flutter::EncodableMap> EchoNonNullStringMap( + const ::flutter::EncodableMap& string_map) = 0; // Returns the passed map, to test serialization and deserialization. - virtual ErrorOr EchoNonNullIntMap( - const flutter::EncodableMap& int_map) = 0; + virtual ErrorOr<::flutter::EncodableMap> EchoNonNullIntMap( + const ::flutter::EncodableMap& int_map) = 0; // Returns the passed map, to test serialization and deserialization. - virtual ErrorOr EchoNonNullEnumMap( - const flutter::EncodableMap& enum_map) = 0; + virtual ErrorOr<::flutter::EncodableMap> EchoNonNullEnumMap( + const ::flutter::EncodableMap& enum_map) = 0; // Returns the passed map, to test serialization and deserialization. - virtual ErrorOr EchoNonNullClassMap( - const flutter::EncodableMap& class_map) = 0; + virtual ErrorOr<::flutter::EncodableMap> EchoNonNullClassMap( + const ::flutter::EncodableMap& class_map) = 0; // Returns the passed class to test nested class serialization and // deserialization. virtual ErrorOr EchoClassWrapper( @@ -875,6 +915,15 @@ class HostIntegrationCoreApi { virtual ErrorOr EchoOptionalDefaultDouble(double a_double) = 0; // Returns passed in int. virtual ErrorOr EchoRequiredInt(int64_t an_int) = 0; + // Returns the result of platform-side equality check. + virtual ErrorOr AreAllNullableTypesEqual(const AllNullableTypes& a, + const AllNullableTypes& b) = 0; + // Returns the platform-side hash code for the given object. + virtual ErrorOr GetAllNullableTypesHash( + const AllNullableTypes& value) = 0; + // Returns the platform-side hash code for the given object. + virtual ErrorOr GetAllNullableTypesWithoutRecursionHash( + const AllNullableTypesWithoutRecursion& value) = 0; // Returns the passed object, to test serialization and deserialization. virtual ErrorOr> EchoAllNullableTypes( const AllNullableTypes* everything) = 0; @@ -915,50 +964,50 @@ class HostIntegrationCoreApi { virtual ErrorOr>> EchoNullableUint8List( const std::vector* a_nullable_uint8_list) = 0; // Returns the passed in generic Object. - virtual ErrorOr> EchoNullableObject( - const flutter::EncodableValue* a_nullable_object) = 0; + virtual ErrorOr> EchoNullableObject( + const ::flutter::EncodableValue* a_nullable_object) = 0; // Returns the passed list, to test serialization and deserialization. - virtual ErrorOr> EchoNullableList( - const flutter::EncodableList* a_nullable_list) = 0; + virtual ErrorOr> EchoNullableList( + const ::flutter::EncodableList* a_nullable_list) = 0; // Returns the passed list, to test serialization and deserialization. - virtual ErrorOr> EchoNullableEnumList( - const flutter::EncodableList* enum_list) = 0; + virtual ErrorOr> EchoNullableEnumList( + const ::flutter::EncodableList* enum_list) = 0; // Returns the passed list, to test serialization and deserialization. - virtual ErrorOr> EchoNullableClassList( - const flutter::EncodableList* class_list) = 0; + virtual ErrorOr> + EchoNullableClassList(const ::flutter::EncodableList* class_list) = 0; // Returns the passed list, to test serialization and deserialization. - virtual ErrorOr> - EchoNullableNonNullEnumList(const flutter::EncodableList* enum_list) = 0; + virtual ErrorOr> + EchoNullableNonNullEnumList(const ::flutter::EncodableList* enum_list) = 0; // Returns the passed list, to test serialization and deserialization. - virtual ErrorOr> - EchoNullableNonNullClassList(const flutter::EncodableList* class_list) = 0; + virtual ErrorOr> + EchoNullableNonNullClassList(const ::flutter::EncodableList* class_list) = 0; // Returns the passed map, to test serialization and deserialization. - virtual ErrorOr> EchoNullableMap( - const flutter::EncodableMap* map) = 0; + virtual ErrorOr> EchoNullableMap( + const ::flutter::EncodableMap* map) = 0; // Returns the passed map, to test serialization and deserialization. - virtual ErrorOr> EchoNullableStringMap( - const flutter::EncodableMap* string_map) = 0; + virtual ErrorOr> EchoNullableStringMap( + const ::flutter::EncodableMap* string_map) = 0; // Returns the passed map, to test serialization and deserialization. - virtual ErrorOr> EchoNullableIntMap( - const flutter::EncodableMap* int_map) = 0; + virtual ErrorOr> EchoNullableIntMap( + const ::flutter::EncodableMap* int_map) = 0; // Returns the passed map, to test serialization and deserialization. - virtual ErrorOr> EchoNullableEnumMap( - const flutter::EncodableMap* enum_map) = 0; + virtual ErrorOr> EchoNullableEnumMap( + const ::flutter::EncodableMap* enum_map) = 0; // Returns the passed map, to test serialization and deserialization. - virtual ErrorOr> EchoNullableClassMap( - const flutter::EncodableMap* class_map) = 0; + virtual ErrorOr> EchoNullableClassMap( + const ::flutter::EncodableMap* class_map) = 0; // Returns the passed map, to test serialization and deserialization. - virtual ErrorOr> - EchoNullableNonNullStringMap(const flutter::EncodableMap* string_map) = 0; + virtual ErrorOr> + EchoNullableNonNullStringMap(const ::flutter::EncodableMap* string_map) = 0; // Returns the passed map, to test serialization and deserialization. - virtual ErrorOr> - EchoNullableNonNullIntMap(const flutter::EncodableMap* int_map) = 0; + virtual ErrorOr> + EchoNullableNonNullIntMap(const ::flutter::EncodableMap* int_map) = 0; // Returns the passed map, to test serialization and deserialization. - virtual ErrorOr> - EchoNullableNonNullEnumMap(const flutter::EncodableMap* enum_map) = 0; + virtual ErrorOr> + EchoNullableNonNullEnumMap(const ::flutter::EncodableMap* enum_map) = 0; // Returns the passed map, to test serialization and deserialization. - virtual ErrorOr> - EchoNullableNonNullClassMap(const flutter::EncodableMap* class_map) = 0; + virtual ErrorOr> + EchoNullableNonNullClassMap(const ::flutter::EncodableMap* class_map) = 0; virtual ErrorOr> EchoNullableEnum( const AnEnum* an_enum) = 0; virtual ErrorOr> EchoAnotherNullableEnum( @@ -992,48 +1041,48 @@ class HostIntegrationCoreApi { std::function> reply)> result) = 0; // Returns the passed in generic Object asynchronously. virtual void EchoAsyncObject( - const flutter::EncodableValue& an_object, - std::function reply)> result) = 0; + const ::flutter::EncodableValue& an_object, + std::function reply)> result) = 0; // Returns the passed list, to test asynchronous serialization and // deserialization. virtual void EchoAsyncList( - const flutter::EncodableList& list, - std::function reply)> result) = 0; + const ::flutter::EncodableList& list, + std::function reply)> result) = 0; // Returns the passed list, to test asynchronous serialization and // deserialization. virtual void EchoAsyncEnumList( - const flutter::EncodableList& enum_list, - std::function reply)> result) = 0; + const ::flutter::EncodableList& enum_list, + std::function reply)> result) = 0; // Returns the passed list, to test asynchronous serialization and // deserialization. virtual void EchoAsyncClassList( - const flutter::EncodableList& class_list, - std::function reply)> result) = 0; + const ::flutter::EncodableList& class_list, + std::function reply)> result) = 0; // Returns the passed map, to test asynchronous serialization and // deserialization. virtual void EchoAsyncMap( - const flutter::EncodableMap& map, - std::function reply)> result) = 0; + const ::flutter::EncodableMap& map, + std::function reply)> result) = 0; // Returns the passed map, to test asynchronous serialization and // deserialization. virtual void EchoAsyncStringMap( - const flutter::EncodableMap& string_map, - std::function reply)> result) = 0; + const ::flutter::EncodableMap& string_map, + std::function reply)> result) = 0; // Returns the passed map, to test asynchronous serialization and // deserialization. virtual void EchoAsyncIntMap( - const flutter::EncodableMap& int_map, - std::function reply)> result) = 0; + const ::flutter::EncodableMap& int_map, + std::function reply)> result) = 0; // Returns the passed map, to test asynchronous serialization and // deserialization. virtual void EchoAsyncEnumMap( - const flutter::EncodableMap& enum_map, - std::function reply)> result) = 0; + const ::flutter::EncodableMap& enum_map, + std::function reply)> result) = 0; // Returns the passed map, to test asynchronous serialization and // deserialization. virtual void EchoAsyncClassMap( - const flutter::EncodableMap& class_map, - std::function reply)> result) = 0; + const ::flutter::EncodableMap& class_map, + std::function reply)> result) = 0; // Returns the passed enum, to test asynchronous serialization and // deserialization. virtual void EchoAsyncEnum( @@ -1046,14 +1095,16 @@ class HostIntegrationCoreApi { std::function reply)> result) = 0; // Responds with an error from an async function returning a value. virtual void ThrowAsyncError( - std::function> reply)> + std::function< + void(ErrorOr> reply)> result) = 0; // Responds with an error from an async void function. virtual void ThrowAsyncErrorFromVoid( std::function reply)> result) = 0; // Responds with a Flutter error from an async function returning a value. virtual void ThrowAsyncFlutterError( - std::function> reply)> + std::function< + void(ErrorOr> reply)> result) = 0; // Returns the passed object, to test async serialization and deserialization. virtual void EchoAsyncAllTypes( @@ -1094,56 +1145,60 @@ class HostIntegrationCoreApi { result) = 0; // Returns the passed in generic Object asynchronously. virtual void EchoAsyncNullableObject( - const flutter::EncodableValue* an_object, - std::function> reply)> + const ::flutter::EncodableValue* an_object, + std::function< + void(ErrorOr> reply)> result) = 0; // Returns the passed list, to test asynchronous serialization and // deserialization. virtual void EchoAsyncNullableList( - const flutter::EncodableList* list, - std::function> reply)> + const ::flutter::EncodableList* list, + std::function< + void(ErrorOr> reply)> result) = 0; // Returns the passed list, to test asynchronous serialization and // deserialization. virtual void EchoAsyncNullableEnumList( - const flutter::EncodableList* enum_list, - std::function> reply)> + const ::flutter::EncodableList* enum_list, + std::function< + void(ErrorOr> reply)> result) = 0; // Returns the passed list, to test asynchronous serialization and // deserialization. virtual void EchoAsyncNullableClassList( - const flutter::EncodableList* class_list, - std::function> reply)> + const ::flutter::EncodableList* class_list, + std::function< + void(ErrorOr> reply)> result) = 0; // Returns the passed map, to test asynchronous serialization and // deserialization. virtual void EchoAsyncNullableMap( - const flutter::EncodableMap* map, - std::function> reply)> + const ::flutter::EncodableMap* map, + std::function> reply)> result) = 0; // Returns the passed map, to test asynchronous serialization and // deserialization. virtual void EchoAsyncNullableStringMap( - const flutter::EncodableMap* string_map, - std::function> reply)> + const ::flutter::EncodableMap* string_map, + std::function> reply)> result) = 0; // Returns the passed map, to test asynchronous serialization and // deserialization. virtual void EchoAsyncNullableIntMap( - const flutter::EncodableMap* int_map, - std::function> reply)> + const ::flutter::EncodableMap* int_map, + std::function> reply)> result) = 0; // Returns the passed map, to test asynchronous serialization and // deserialization. virtual void EchoAsyncNullableEnumMap( - const flutter::EncodableMap* enum_map, - std::function> reply)> + const ::flutter::EncodableMap* enum_map, + std::function> reply)> result) = 0; // Returns the passed map, to test asynchronous serialization and // deserialization. virtual void EchoAsyncNullableClassMap( - const flutter::EncodableMap* class_map, - std::function> reply)> + const ::flutter::EncodableMap* class_map, + std::function> reply)> result) = 0; // Returns the passed enum, to test asynchronous serialization and // deserialization. @@ -1165,7 +1220,8 @@ class HostIntegrationCoreApi { virtual void CallFlutterNoop( std::function reply)> result) = 0; virtual void CallFlutterThrowError( - std::function> reply)> + std::function< + void(ErrorOr> reply)> result) = 0; virtual void CallFlutterThrowErrorFromVoid( std::function reply)> result) = 0; @@ -1203,47 +1259,47 @@ class HostIntegrationCoreApi { const std::vector& list, std::function> reply)> result) = 0; virtual void CallFlutterEchoList( - const flutter::EncodableList& list, - std::function reply)> result) = 0; + const ::flutter::EncodableList& list, + std::function reply)> result) = 0; virtual void CallFlutterEchoEnumList( - const flutter::EncodableList& enum_list, - std::function reply)> result) = 0; + const ::flutter::EncodableList& enum_list, + std::function reply)> result) = 0; virtual void CallFlutterEchoClassList( - const flutter::EncodableList& class_list, - std::function reply)> result) = 0; + const ::flutter::EncodableList& class_list, + std::function reply)> result) = 0; virtual void CallFlutterEchoNonNullEnumList( - const flutter::EncodableList& enum_list, - std::function reply)> result) = 0; + const ::flutter::EncodableList& enum_list, + std::function reply)> result) = 0; virtual void CallFlutterEchoNonNullClassList( - const flutter::EncodableList& class_list, - std::function reply)> result) = 0; + const ::flutter::EncodableList& class_list, + std::function reply)> result) = 0; virtual void CallFlutterEchoMap( - const flutter::EncodableMap& map, - std::function reply)> result) = 0; + const ::flutter::EncodableMap& map, + std::function reply)> result) = 0; virtual void CallFlutterEchoStringMap( - const flutter::EncodableMap& string_map, - std::function reply)> result) = 0; + const ::flutter::EncodableMap& string_map, + std::function reply)> result) = 0; virtual void CallFlutterEchoIntMap( - const flutter::EncodableMap& int_map, - std::function reply)> result) = 0; + const ::flutter::EncodableMap& int_map, + std::function reply)> result) = 0; virtual void CallFlutterEchoEnumMap( - const flutter::EncodableMap& enum_map, - std::function reply)> result) = 0; + const ::flutter::EncodableMap& enum_map, + std::function reply)> result) = 0; virtual void CallFlutterEchoClassMap( - const flutter::EncodableMap& class_map, - std::function reply)> result) = 0; + const ::flutter::EncodableMap& class_map, + std::function reply)> result) = 0; virtual void CallFlutterEchoNonNullStringMap( - const flutter::EncodableMap& string_map, - std::function reply)> result) = 0; + const ::flutter::EncodableMap& string_map, + std::function reply)> result) = 0; virtual void CallFlutterEchoNonNullIntMap( - const flutter::EncodableMap& int_map, - std::function reply)> result) = 0; + const ::flutter::EncodableMap& int_map, + std::function reply)> result) = 0; virtual void CallFlutterEchoNonNullEnumMap( - const flutter::EncodableMap& enum_map, - std::function reply)> result) = 0; + const ::flutter::EncodableMap& enum_map, + std::function reply)> result) = 0; virtual void CallFlutterEchoNonNullClassMap( - const flutter::EncodableMap& class_map, - std::function reply)> result) = 0; + const ::flutter::EncodableMap& class_map, + std::function reply)> result) = 0; virtual void CallFlutterEchoEnum( const AnEnum& an_enum, std::function reply)> result) = 0; @@ -1268,60 +1324,65 @@ class HostIntegrationCoreApi { std::function>> reply)> result) = 0; virtual void CallFlutterEchoNullableList( - const flutter::EncodableList* list, - std::function> reply)> + const ::flutter::EncodableList* list, + std::function< + void(ErrorOr> reply)> result) = 0; virtual void CallFlutterEchoNullableEnumList( - const flutter::EncodableList* enum_list, - std::function> reply)> + const ::flutter::EncodableList* enum_list, + std::function< + void(ErrorOr> reply)> result) = 0; virtual void CallFlutterEchoNullableClassList( - const flutter::EncodableList* class_list, - std::function> reply)> + const ::flutter::EncodableList* class_list, + std::function< + void(ErrorOr> reply)> result) = 0; virtual void CallFlutterEchoNullableNonNullEnumList( - const flutter::EncodableList* enum_list, - std::function> reply)> + const ::flutter::EncodableList* enum_list, + std::function< + void(ErrorOr> reply)> result) = 0; virtual void CallFlutterEchoNullableNonNullClassList( - const flutter::EncodableList* class_list, - std::function> reply)> + const ::flutter::EncodableList* class_list, + std::function< + void(ErrorOr> reply)> result) = 0; virtual void CallFlutterEchoNullableMap( - const flutter::EncodableMap* map, - std::function> reply)> + const ::flutter::EncodableMap* map, + std::function> reply)> result) = 0; virtual void CallFlutterEchoNullableStringMap( - const flutter::EncodableMap* string_map, - std::function> reply)> + const ::flutter::EncodableMap* string_map, + std::function> reply)> result) = 0; virtual void CallFlutterEchoNullableIntMap( - const flutter::EncodableMap* int_map, - std::function> reply)> + const ::flutter::EncodableMap* int_map, + std::function> reply)> result) = 0; virtual void CallFlutterEchoNullableEnumMap( - const flutter::EncodableMap* enum_map, - std::function> reply)> + const ::flutter::EncodableMap* enum_map, + std::function> reply)> result) = 0; virtual void CallFlutterEchoNullableClassMap( - const flutter::EncodableMap* class_map, - std::function> reply)> + const ::flutter::EncodableMap* class_map, + std::function> reply)> result) = 0; virtual void CallFlutterEchoNullableNonNullStringMap( - const flutter::EncodableMap* string_map, - std::function> reply)> + const ::flutter::EncodableMap* string_map, + std::function> reply)> result) = 0; virtual void CallFlutterEchoNullableNonNullIntMap( - const flutter::EncodableMap* int_map, - std::function> reply)> + const ::flutter::EncodableMap* int_map, + std::function> reply)> result) = 0; virtual void CallFlutterEchoNullableNonNullEnumMap( - const flutter::EncodableMap* enum_map, - std::function> reply)> + const ::flutter::EncodableMap* enum_map, + std::function> reply)> result) = 0; virtual void CallFlutterEchoNullableNonNullClassMap( - const flutter::EncodableMap* class_map, - std::function> reply)> + const ::flutter::EncodableMap* class_map, + std::function> reply)> result) = 0; virtual void CallFlutterEchoNullableEnum( const AnEnum* an_enum, @@ -1335,16 +1396,16 @@ class HostIntegrationCoreApi { std::function reply)> result) = 0; // The codec used by HostIntegrationCoreApi. - static const flutter::StandardMessageCodec& GetCodec(); + static const ::flutter::StandardMessageCodec& GetCodec(); // Sets up an instance of `HostIntegrationCoreApi` to handle messages through // the `binary_messenger`. - static void SetUp(flutter::BinaryMessenger* binary_messenger, + static void SetUp(::flutter::BinaryMessenger* binary_messenger, HostIntegrationCoreApi* api); - static void SetUp(flutter::BinaryMessenger* binary_messenger, + static void SetUp(::flutter::BinaryMessenger* binary_messenger, HostIntegrationCoreApi* api, const std::string& message_channel_suffix); - static flutter::EncodableValue WrapError(std::string_view error_message); - static flutter::EncodableValue WrapError(const FlutterError& error); + static ::flutter::EncodableValue WrapError(std::string_view error_message); + static ::flutter::EncodableValue WrapError(const FlutterError& error); protected: HostIntegrationCoreApi() = default; @@ -1356,17 +1417,17 @@ class HostIntegrationCoreApi { // called from C++. class FlutterIntegrationCoreApi { public: - FlutterIntegrationCoreApi(flutter::BinaryMessenger* binary_messenger); - FlutterIntegrationCoreApi(flutter::BinaryMessenger* binary_messenger, + FlutterIntegrationCoreApi(::flutter::BinaryMessenger* binary_messenger); + FlutterIntegrationCoreApi(::flutter::BinaryMessenger* binary_messenger, const std::string& message_channel_suffix); - static const flutter::StandardMessageCodec& GetCodec(); + static const ::flutter::StandardMessageCodec& GetCodec(); // A no-op function taking no arguments and returning no value, to sanity // test basic calling. void Noop(std::function&& on_success, std::function&& on_error); // Responds with an error from an async function returning a value. void ThrowError( - std::function&& on_success, + std::function&& on_success, std::function&& on_error); // Responds with an error from an async void function. void ThrowErrorFromVoid(std::function&& on_success, @@ -1420,72 +1481,73 @@ class FlutterIntegrationCoreApi { std::function&)>&& on_success, std::function&& on_error); // Returns the passed list, to test serialization and deserialization. - void EchoList(const flutter::EncodableList& list, - std::function&& on_success, - std::function&& on_error); + void EchoList( + const ::flutter::EncodableList& list, + std::function&& on_success, + std::function&& on_error); // Returns the passed list, to test serialization and deserialization. void EchoEnumList( - const flutter::EncodableList& enum_list, - std::function&& on_success, + const ::flutter::EncodableList& enum_list, + std::function&& on_success, std::function&& on_error); // Returns the passed list, to test serialization and deserialization. void EchoClassList( - const flutter::EncodableList& class_list, - std::function&& on_success, + const ::flutter::EncodableList& class_list, + std::function&& on_success, std::function&& on_error); // Returns the passed list, to test serialization and deserialization. void EchoNonNullEnumList( - const flutter::EncodableList& enum_list, - std::function&& on_success, + const ::flutter::EncodableList& enum_list, + std::function&& on_success, std::function&& on_error); // Returns the passed list, to test serialization and deserialization. void EchoNonNullClassList( - const flutter::EncodableList& class_list, - std::function&& on_success, + const ::flutter::EncodableList& class_list, + std::function&& on_success, std::function&& on_error); // Returns the passed map, to test serialization and deserialization. - void EchoMap(const flutter::EncodableMap& map, - std::function&& on_success, + void EchoMap(const ::flutter::EncodableMap& map, + std::function&& on_success, std::function&& on_error); // Returns the passed map, to test serialization and deserialization. void EchoStringMap( - const flutter::EncodableMap& string_map, - std::function&& on_success, + const ::flutter::EncodableMap& string_map, + std::function&& on_success, std::function&& on_error); // Returns the passed map, to test serialization and deserialization. void EchoIntMap( - const flutter::EncodableMap& int_map, - std::function&& on_success, + const ::flutter::EncodableMap& int_map, + std::function&& on_success, std::function&& on_error); // Returns the passed map, to test serialization and deserialization. void EchoEnumMap( - const flutter::EncodableMap& enum_map, - std::function&& on_success, + const ::flutter::EncodableMap& enum_map, + std::function&& on_success, std::function&& on_error); // Returns the passed map, to test serialization and deserialization. void EchoClassMap( - const flutter::EncodableMap& class_map, - std::function&& on_success, + const ::flutter::EncodableMap& class_map, + std::function&& on_success, std::function&& on_error); // Returns the passed map, to test serialization and deserialization. void EchoNonNullStringMap( - const flutter::EncodableMap& string_map, - std::function&& on_success, + const ::flutter::EncodableMap& string_map, + std::function&& on_success, std::function&& on_error); // Returns the passed map, to test serialization and deserialization. void EchoNonNullIntMap( - const flutter::EncodableMap& int_map, - std::function&& on_success, + const ::flutter::EncodableMap& int_map, + std::function&& on_success, std::function&& on_error); // Returns the passed map, to test serialization and deserialization. void EchoNonNullEnumMap( - const flutter::EncodableMap& enum_map, - std::function&& on_success, + const ::flutter::EncodableMap& enum_map, + std::function&& on_success, std::function&& on_error); // Returns the passed map, to test serialization and deserialization. void EchoNonNullClassMap( - const flutter::EncodableMap& class_map, - std::function&& on_success, + const ::flutter::EncodableMap& class_map, + std::function&& on_success, std::function&& on_error); // Returns the passed enum to test serialization and deserialization. void EchoEnum(const AnEnum& an_enum, @@ -1518,73 +1580,73 @@ class FlutterIntegrationCoreApi { std::function&& on_error); // Returns the passed list, to test serialization and deserialization. void EchoNullableList( - const flutter::EncodableList* list, - std::function&& on_success, + const ::flutter::EncodableList* list, + std::function&& on_success, std::function&& on_error); // Returns the passed list, to test serialization and deserialization. void EchoNullableEnumList( - const flutter::EncodableList* enum_list, - std::function&& on_success, + const ::flutter::EncodableList* enum_list, + std::function&& on_success, std::function&& on_error); // Returns the passed list, to test serialization and deserialization. void EchoNullableClassList( - const flutter::EncodableList* class_list, - std::function&& on_success, + const ::flutter::EncodableList* class_list, + std::function&& on_success, std::function&& on_error); // Returns the passed list, to test serialization and deserialization. void EchoNullableNonNullEnumList( - const flutter::EncodableList* enum_list, - std::function&& on_success, + const ::flutter::EncodableList* enum_list, + std::function&& on_success, std::function&& on_error); // Returns the passed list, to test serialization and deserialization. void EchoNullableNonNullClassList( - const flutter::EncodableList* class_list, - std::function&& on_success, + const ::flutter::EncodableList* class_list, + std::function&& on_success, std::function&& on_error); // Returns the passed map, to test serialization and deserialization. void EchoNullableMap( - const flutter::EncodableMap* map, - std::function&& on_success, + const ::flutter::EncodableMap* map, + std::function&& on_success, std::function&& on_error); // Returns the passed map, to test serialization and deserialization. void EchoNullableStringMap( - const flutter::EncodableMap* string_map, - std::function&& on_success, + const ::flutter::EncodableMap* string_map, + std::function&& on_success, std::function&& on_error); // Returns the passed map, to test serialization and deserialization. void EchoNullableIntMap( - const flutter::EncodableMap* int_map, - std::function&& on_success, + const ::flutter::EncodableMap* int_map, + std::function&& on_success, std::function&& on_error); // Returns the passed map, to test serialization and deserialization. void EchoNullableEnumMap( - const flutter::EncodableMap* enum_map, - std::function&& on_success, + const ::flutter::EncodableMap* enum_map, + std::function&& on_success, std::function&& on_error); // Returns the passed map, to test serialization and deserialization. void EchoNullableClassMap( - const flutter::EncodableMap* class_map, - std::function&& on_success, + const ::flutter::EncodableMap* class_map, + std::function&& on_success, std::function&& on_error); // Returns the passed map, to test serialization and deserialization. void EchoNullableNonNullStringMap( - const flutter::EncodableMap* string_map, - std::function&& on_success, + const ::flutter::EncodableMap* string_map, + std::function&& on_success, std::function&& on_error); // Returns the passed map, to test serialization and deserialization. void EchoNullableNonNullIntMap( - const flutter::EncodableMap* int_map, - std::function&& on_success, + const ::flutter::EncodableMap* int_map, + std::function&& on_success, std::function&& on_error); // Returns the passed map, to test serialization and deserialization. void EchoNullableNonNullEnumMap( - const flutter::EncodableMap* enum_map, - std::function&& on_success, + const ::flutter::EncodableMap* enum_map, + std::function&& on_success, std::function&& on_error); // Returns the passed map, to test serialization and deserialization. void EchoNullableNonNullClassMap( - const flutter::EncodableMap* class_map, - std::function&& on_success, + const ::flutter::EncodableMap* class_map, + std::function&& on_success, std::function&& on_error); // Returns the passed enum to test serialization and deserialization. void EchoNullableEnum(const AnEnum* an_enum, @@ -1605,7 +1667,7 @@ class FlutterIntegrationCoreApi { std::function&& on_error); private: - flutter::BinaryMessenger* binary_messenger_; + ::flutter::BinaryMessenger* binary_messenger_; std::string message_channel_suffix_; }; @@ -1621,16 +1683,16 @@ class HostTrivialApi { virtual std::optional Noop() = 0; // The codec used by HostTrivialApi. - static const flutter::StandardMessageCodec& GetCodec(); + static const ::flutter::StandardMessageCodec& GetCodec(); // Sets up an instance of `HostTrivialApi` to handle messages through the // `binary_messenger`. - static void SetUp(flutter::BinaryMessenger* binary_messenger, + static void SetUp(::flutter::BinaryMessenger* binary_messenger, HostTrivialApi* api); - static void SetUp(flutter::BinaryMessenger* binary_messenger, + static void SetUp(::flutter::BinaryMessenger* binary_messenger, HostTrivialApi* api, const std::string& message_channel_suffix); - static flutter::EncodableValue WrapError(std::string_view error_message); - static flutter::EncodableValue WrapError(const FlutterError& error); + static ::flutter::EncodableValue WrapError(std::string_view error_message); + static ::flutter::EncodableValue WrapError(const FlutterError& error); protected: HostTrivialApi() = default; @@ -1650,16 +1712,16 @@ class HostSmallApi { std::function reply)> result) = 0; // The codec used by HostSmallApi. - static const flutter::StandardMessageCodec& GetCodec(); + static const ::flutter::StandardMessageCodec& GetCodec(); // Sets up an instance of `HostSmallApi` to handle messages through the // `binary_messenger`. - static void SetUp(flutter::BinaryMessenger* binary_messenger, + static void SetUp(::flutter::BinaryMessenger* binary_messenger, HostSmallApi* api); - static void SetUp(flutter::BinaryMessenger* binary_messenger, + static void SetUp(::flutter::BinaryMessenger* binary_messenger, HostSmallApi* api, const std::string& message_channel_suffix); - static flutter::EncodableValue WrapError(std::string_view error_message); - static flutter::EncodableValue WrapError(const FlutterError& error); + static ::flutter::EncodableValue WrapError(std::string_view error_message); + static ::flutter::EncodableValue WrapError(const FlutterError& error); protected: HostSmallApi() = default; @@ -1670,10 +1732,10 @@ class HostSmallApi { // called from C++. class FlutterSmallApi { public: - FlutterSmallApi(flutter::BinaryMessenger* binary_messenger); - FlutterSmallApi(flutter::BinaryMessenger* binary_messenger, + FlutterSmallApi(::flutter::BinaryMessenger* binary_messenger); + FlutterSmallApi(::flutter::BinaryMessenger* binary_messenger, const std::string& message_channel_suffix); - static const flutter::StandardMessageCodec& GetCodec(); + static const ::flutter::StandardMessageCodec& GetCodec(); void EchoWrappedList(const TestMessage& msg, std::function&& on_success, std::function&& on_error); @@ -1682,7 +1744,7 @@ class FlutterSmallApi { std::function&& on_error); private: - flutter::BinaryMessenger* binary_messenger_; + ::flutter::BinaryMessenger* binary_messenger_; std::string message_channel_suffix_; }; diff --git a/packages/pigeon/platform_tests/test_plugin/windows/test/equality_test.cpp b/packages/pigeon/platform_tests/test_plugin/windows/test/equality_test.cpp new file mode 100644 index 000000000000..79cfe24f9cb8 --- /dev/null +++ b/packages/pigeon/platform_tests/test_plugin/windows/test/equality_test.cpp @@ -0,0 +1,104 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include + +#include + +#include "pigeon/core_tests.gen.h" + +namespace test_plugin { +namespace test { + +using namespace core_tests_pigeontest; + +TEST(EqualityTests, NaNEquality) { + AllNullableTypes all1; + all1.set_a_nullable_double(NAN); + + AllNullableTypes all2; + all2.set_a_nullable_double(NAN); + + EXPECT_EQ(all1, all2); + + AllNullableTypes all3; + all3.set_a_nullable_double(1.0); + + EXPECT_NE(all1, all3); +} + +TEST(EqualityTests, OptionalNaNEquality) { + AllNullableTypes all1; + // std::optional handled via set_a_nullable_double + all1.set_a_nullable_double(NAN); + + AllNullableTypes all2; + all2.set_a_nullable_double(NAN); + + EXPECT_EQ(all1, all2); +} + +TEST(EqualityTests, NestedNaNEquality) { + std::vector list = {NAN}; + AllNullableTypes all1; + all1.set_double_list(list); + + AllNullableTypes all2; + all2.set_double_list(list); + + EXPECT_EQ(all1, all2); +} + +TEST(EqualityTests, SignedZeroEquality) { + AllNullableTypes all1; + all1.set_a_nullable_double(0.0); + + AllNullableTypes all2; + all2.set_a_nullable_double(-0.0); + + EXPECT_EQ(all1, all2); +} + +TEST(EqualityTests, NestedZeroListEquality) { + std::vector list1 = {0.0}; + AllNullableTypes all1; + all1.set_double_list(list1); + + std::vector list2 = {-0.0}; + AllNullableTypes all2; + all2.set_double_list(list2); + + EXPECT_EQ(all1, all2); +} + +TEST(EqualityTests, ZeroMapKeyEquality) { + std::map map1; + map1[flutter::EncodableValue(0.0)] = flutter::EncodableValue("a"); + AllNullableTypes all1; + all1.set_map(map1); + + std::map map2; + map2[flutter::EncodableValue(-0.0)] = flutter::EncodableValue("a"); + AllNullableTypes all2; + all2.set_map(map2); + + EXPECT_EQ(all1, all2); +} + +TEST(EqualityTests, ZeroMapValueEquality) { + std::map map1; + map1[flutter::EncodableValue("a")] = flutter::EncodableValue(0.0); + AllNullableTypes all1; + all1.set_map(map1); + + std::map map2; + map2[flutter::EncodableValue("a")] = flutter::EncodableValue(-0.0); + AllNullableTypes all2; + all2.set_map(map2); + + EXPECT_EQ(all1, all2); +} + +} // namespace test +} // namespace test_plugin diff --git a/packages/pigeon/platform_tests/test_plugin/windows/test/non_null_fields_test.cpp b/packages/pigeon/platform_tests/test_plugin/windows/test/non_null_fields_test.cpp index 07412dc84378..d7ea926f62b3 100644 --- a/packages/pigeon/platform_tests/test_plugin/windows/test/non_null_fields_test.cpp +++ b/packages/pigeon/platform_tests/test_plugin/windows/test/non_null_fields_test.cpp @@ -14,4 +14,13 @@ TEST(NonNullFields, Build) { EXPECT_EQ(request.query(), "hello"); } +TEST(NonNullFields, Equality) { + NonNullFieldSearchRequest request1("hello"); + NonNullFieldSearchRequest request2("hello"); + NonNullFieldSearchRequest request3("world"); + + EXPECT_EQ(request1, request2); + EXPECT_NE(request1, request3); +} + } // namespace non_null_fields_pigeontest diff --git a/packages/pigeon/platform_tests/test_plugin/windows/test/null_fields_test.cpp b/packages/pigeon/platform_tests/test_plugin/windows/test/null_fields_test.cpp index 9a0cf75e8259..46f16079cc45 100644 --- a/packages/pigeon/platform_tests/test_plugin/windows/test/null_fields_test.cpp +++ b/packages/pigeon/platform_tests/test_plugin/windows/test/null_fields_test.cpp @@ -211,4 +211,34 @@ TEST_F(NullFieldsTest, ReplyToListWithNulls) { } } +TEST(NullFields, Equality) { + NullFieldsSearchRequest request1(1); + request1.set_query("hello"); + NullFieldsSearchRequest request2(1); + request2.set_query("hello"); + NullFieldsSearchRequest request3(2); + request3.set_query("hello"); + NullFieldsSearchRequest request4(1); + request4.set_query("world"); + + EXPECT_EQ(request1, request2); + EXPECT_FALSE(request1 == request3); + EXPECT_FALSE(request1 == request4); + + NullFieldsSearchReply reply1; + reply1.set_result("result"); + reply1.set_request(request1); + + NullFieldsSearchReply reply2; + reply2.set_result("result"); + reply2.set_request(request2); + + NullFieldsSearchReply reply3; + reply3.set_result("result"); + reply3.set_request(request3); + + EXPECT_EQ(reply1, reply2); + EXPECT_FALSE(reply1 == reply3); +} + } // namespace null_fields_pigeontest diff --git a/packages/pigeon/platform_tests/test_plugin/windows/test_plugin.cpp b/packages/pigeon/platform_tests/test_plugin/windows/test_plugin.cpp index bb77ea902dfc..3e6056f3a810 100644 --- a/packages/pigeon/platform_tests/test_plugin/windows/test_plugin.cpp +++ b/packages/pigeon/platform_tests/test_plugin/windows/test_plugin.cpp @@ -97,6 +97,21 @@ ErrorOr> TestPlugin::EchoAllNullableTypes( return std::optional(*everything); } +ErrorOr TestPlugin::AreAllNullableTypesEqual(const AllNullableTypes& a, + const AllNullableTypes& b) { + return a == b; +} + +ErrorOr TestPlugin::GetAllNullableTypesHash( + const AllNullableTypes& value) { + return (int64_t)value.Hash(); +} + +ErrorOr TestPlugin::GetAllNullableTypesWithoutRecursionHash( + const AllNullableTypesWithoutRecursion& value) { + return (int64_t)value.Hash(); +} + ErrorOr> TestPlugin::EchoAllNullableTypesWithoutRecursion( const AllNullableTypesWithoutRecursion* everything) { diff --git a/packages/pigeon/platform_tests/test_plugin/windows/test_plugin.h b/packages/pigeon/platform_tests/test_plugin/windows/test_plugin.h index 002a73291335..a52bd83f03a2 100644 --- a/packages/pigeon/platform_tests/test_plugin/windows/test_plugin.h +++ b/packages/pigeon/platform_tests/test_plugin/windows/test_plugin.h @@ -60,6 +60,15 @@ class TestPlugin : public flutter::Plugin, std::optional> EchoAllNullableTypes( const core_tests_pigeontest::AllNullableTypes* everything) override; + core_tests_pigeontest::ErrorOr AreAllNullableTypesEqual( + const core_tests_pigeontest::AllNullableTypes& a, + const core_tests_pigeontest::AllNullableTypes& b) override; + core_tests_pigeontest::ErrorOr GetAllNullableTypesHash( + const core_tests_pigeontest::AllNullableTypes& value) override; + core_tests_pigeontest::ErrorOr + GetAllNullableTypesWithoutRecursionHash( + const core_tests_pigeontest::AllNullableTypesWithoutRecursion& value) + override; core_tests_pigeontest::ErrorOr< std::optional> EchoAllNullableTypesWithoutRecursion( diff --git a/packages/pigeon/pubspec.yaml b/packages/pigeon/pubspec.yaml index d727a2368700..637fb3f6fe6b 100644 --- a/packages/pigeon/pubspec.yaml +++ b/packages/pigeon/pubspec.yaml @@ -2,13 +2,13 @@ name: pigeon description: Code generator tool to make communication between Flutter and the host platform type-safe and easier. repository: https://github.com/flutter/packages/tree/main/packages/pigeon issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+pigeon%22 -version: 26.2.3 # This must match the version in lib/src/generator_tools.dart +version: 26.3.3 # This must match the version in lib/src/generator_tools.dart environment: sdk: ^3.9.0 dependencies: - analyzer: ">=8.0.0 <10.0.0" + analyzer: ">=10.0.0 <13.0.0" args: ^2.5.0 code_builder: ^4.10.0 collection: ^1.15.0 @@ -27,3 +27,4 @@ topics: - interop - platform-channels - plugin-development + diff --git a/packages/pigeon/test/cpp_generator_test.dart b/packages/pigeon/test/cpp_generator_test.dart index d9a22ec657bb..0c77bed2b1de 100644 --- a/packages/pigeon/test/cpp_generator_test.dart +++ b/packages/pigeon/test/cpp_generator_test.dart @@ -124,7 +124,7 @@ void main() { contains( RegExp( r'void Api::SetUp\(\s*' - r'flutter::BinaryMessenger\* binary_messenger,\s*' + r'::flutter::BinaryMessenger\* binary_messenger,\s*' r'Api\* api\s*\)', ), ), @@ -309,12 +309,12 @@ void main() { contains(' const std::string& code() const { return code_; }'), contains(' const std::string& message() const { return message_; }'), contains( - ' const flutter::EncodableValue& details() const { return details_; }', + ' const ::flutter::EncodableValue& details() const { return details_; }', ), contains(' private:'), contains(' std::string code_;'), contains(' std::string message_;'), - contains(' flutter::EncodableValue details_;'), + contains(' ::flutter::EncodableValue details_;'), ]), ); } @@ -567,6 +567,8 @@ void main() { #include #include +#include +#include #include #include #include @@ -1174,13 +1176,13 @@ void main() { expect( code, contains( - 'ErrorOr> ReturnNullableList()', + 'ErrorOr> ReturnNullableList()', ), ); expect( code, contains( - 'ErrorOr> ReturnNullableMap()', + 'ErrorOr> ReturnNullableMap()', ), ); expect( @@ -1297,8 +1299,8 @@ void main() { expect(code, contains('ErrorOr ReturnBool()')); expect(code, contains('ErrorOr ReturnInt()')); expect(code, contains('ErrorOr ReturnString()')); - expect(code, contains('ErrorOr ReturnList()')); - expect(code, contains('ErrorOr ReturnMap()')); + expect(code, contains('ErrorOr<::flutter::EncodableList> ReturnList()')); + expect(code, contains('ErrorOr<::flutter::EncodableMap> ReturnMap()')); expect(code, contains('ErrorOr ReturnDataClass()')); } }); @@ -1415,10 +1417,10 @@ void main() { r'const bool\* a_bool,\s*' r'const int64_t\* an_int,\s*' r'const std::string\* a_string,\s*' - r'const flutter::EncodableList\* a_list,\s*' - r'const flutter::EncodableMap\* a_map,\s*' + r'const ::flutter::EncodableList\* a_list,\s*' + r'const ::flutter::EncodableMap\* a_map,\s*' r'const ParameterObject\* an_object,\s*' - r'const flutter::EncodableValue\* a_generic_object\s*\)', + r'const ::flutter::EncodableValue\* a_generic_object\s*\)', ), ), ); @@ -1611,10 +1613,10 @@ void main() { r'bool a_bool,\s*' r'int64_t an_int,\s*' r'const std::string& a_string,\s*' - r'const flutter::EncodableList& a_list,\s*' - r'const flutter::EncodableMap& a_map,\s*' + r'const ::flutter::EncodableList& a_list,\s*' + r'const ::flutter::EncodableMap& a_map,\s*' r'const ParameterObject& an_object,\s*' - r'const flutter::EncodableValue& a_generic_object\s*\)', + r'const ::flutter::EncodableValue& a_generic_object\s*\)', ), ), ); @@ -1813,10 +1815,10 @@ void main() { // Nullable strings use std::string* rather than std::string_view* // since there's no implicit conversion for pointer types. r'const std::string\* a_string,\s*' - r'const flutter::EncodableList\* a_list,\s*' - r'const flutter::EncodableMap\* a_map,\s*' + r'const ::flutter::EncodableList\* a_list,\s*' + r'const ::flutter::EncodableMap\* a_map,\s*' r'const ParameterObject\* an_object,\s*' - r'const flutter::EncodableValue\* a_generic_object,', + r'const ::flutter::EncodableValue\* a_generic_object,', ), ), ); @@ -2001,10 +2003,10 @@ void main() { // nullable strings. r'const std::string& a_string,\s*' // Non-POD types use const references. - r'const flutter::EncodableList& a_list,\s*' - r'const flutter::EncodableMap& a_map,\s*' + r'const ::flutter::EncodableList& a_list,\s*' + r'const ::flutter::EncodableMap& a_map,\s*' r'const ParameterObject& an_object,\s*' - r'const flutter::EncodableValue& a_generic_object,\s*', + r'const ::flutter::EncodableValue& a_generic_object,\s*', ), ), ); @@ -2313,7 +2315,7 @@ void main() { dartPackageName: DEFAULT_PACKAGE_NAME, ); final code = sink.toString(); - expect(code, contains(' : public flutter::StandardCodecSerializer')); + expect(code, contains(' : public ::flutter::StandardCodecSerializer')); }); test('Does not send unwrapped EncodableLists', () { @@ -2614,4 +2616,170 @@ void main() { ); expect(code, contains('channel.Send')); }); + + test('data class equality', () { + final root = Root( + apis: [], + classes: [ + Class( + name: 'Foo', + fields: [ + NamedType( + type: const TypeDeclaration(baseName: 'int', isNullable: false), + name: 'bar', + ), + ], + ), + ], + enums: [], + ); + { + final sink = StringBuffer(); + const generator = CppGenerator(); + final generatorOptions = OutputFileOptions( + fileType: FileType.header, + languageOptions: const InternalCppOptions( + cppHeaderOut: '', + cppSourceOut: '', + headerIncludePath: '', + ), + ); + generator.generate( + generatorOptions, + root, + sink, + dartPackageName: DEFAULT_PACKAGE_NAME, + ); + final code = sink.toString(); + expect(code, contains('bool operator==(const Foo& other) const;')); + } + { + final sink = StringBuffer(); + const generator = CppGenerator(); + final generatorOptions = OutputFileOptions( + fileType: FileType.source, + languageOptions: const InternalCppOptions( + cppHeaderOut: '', + cppSourceOut: '', + headerIncludePath: '', + ), + ); + generator.generate( + generatorOptions, + root, + sink, + dartPackageName: DEFAULT_PACKAGE_NAME, + ); + final code = sink.toString(); + expect(code, contains('bool Foo::operator==(const Foo& other) const {')); + } + }); + + test('data class equality with pointers', () { + final nested = Class( + name: 'Nested', + fields: [ + NamedType( + type: const TypeDeclaration(baseName: 'int', isNullable: false), + name: 'data', + ), + ], + ); + final root = Root( + apis: [], + classes: [ + Class( + name: 'Foo', + fields: [ + NamedType( + type: TypeDeclaration( + baseName: 'Nested', + isNullable: true, + associatedClass: nested, + ), + name: 'nested', + ), + ], + ), + nested, + ], + enums: [], + ); + final sink = StringBuffer(); + const generator = CppGenerator(); + final generatorOptions = OutputFileOptions( + fileType: FileType.source, + languageOptions: const InternalCppOptions( + cppHeaderOut: '', + cppSourceOut: '', + headerIncludePath: '', + ), + ); + generator.generate( + generatorOptions, + root, + sink, + dartPackageName: DEFAULT_PACKAGE_NAME, + ); + final code = sink.toString(); + expect(code, contains('bool Foo::operator==(const Foo& other) const {')); + }); + + test('data classes implement Hash', () { + final root = Root( + apis: [], + classes: [ + Class( + name: 'Input', + fields: [ + NamedType( + type: const TypeDeclaration(baseName: 'int', isNullable: false), + name: 'field1', + ), + ], + ), + ], + enums: [], + ); + { + final sink = StringBuffer(); + const generator = CppGenerator(); + final generatorOptions = OutputFileOptions( + fileType: FileType.header, + languageOptions: const InternalCppOptions( + headerIncludePath: 'foo.h', + cppHeaderOut: '', + cppSourceOut: '', + ), + ); + generator.generate( + generatorOptions, + root, + sink, + dartPackageName: DEFAULT_PACKAGE_NAME, + ); + final code = sink.toString(); + expect(code, contains('size_t Hash() const;')); + } + { + final sink = StringBuffer(); + const generator = CppGenerator(); + final generatorOptions = OutputFileOptions( + fileType: FileType.source, + languageOptions: const InternalCppOptions( + headerIncludePath: 'foo.h', + cppHeaderOut: '', + cppSourceOut: '', + ), + ); + generator.generate( + generatorOptions, + root, + sink, + dartPackageName: DEFAULT_PACKAGE_NAME, + ); + final code = sink.toString(); + expect(code, contains('size_t Input::Hash() const {')); + } + }); } diff --git a/packages/pigeon/test/dart_generator_test.dart b/packages/pigeon/test/dart_generator_test.dart index 381838b7ac99..f3774fc75c92 100644 --- a/packages/pigeon/test/dart_generator_test.dart +++ b/packages/pigeon/test/dart_generator_test.dart @@ -2091,4 +2091,64 @@ name: foobar expect(code, contains('buffer.putUint8(4);')); expect(code, contains('buffer.putInt64(value);')); }); + + test('data class equality', () { + final classDefinition = Class( + name: 'Foobar', + fields: [ + NamedType( + type: const TypeDeclaration(baseName: 'int', isNullable: true), + name: 'field1', + ), + ], + ); + final root = Root( + apis: [], + classes: [classDefinition], + enums: [], + ); + final sink = StringBuffer(); + const generator = DartGenerator(); + generator.generate( + const InternalDartOptions(ignoreLints: false), + root, + sink, + dartPackageName: DEFAULT_PACKAGE_NAME, + ); + final code = sink.toString(); + expect(code, contains('bool operator ==(Object other) {')); + expect(code, contains('int get hashCode =>')); + }); + + test('data class equality multi-field', () { + final classDefinition = Class( + name: 'Foobar', + fields: [ + NamedType( + type: const TypeDeclaration(baseName: 'int', isNullable: true), + name: 'field1', + ), + NamedType( + type: const TypeDeclaration(baseName: 'String', isNullable: true), + name: 'field2', + ), + ], + ); + final root = Root( + apis: [], + classes: [classDefinition], + enums: [], + ); + final sink = StringBuffer(); + const generator = DartGenerator(); + generator.generate( + const InternalDartOptions(ignoreLints: false), + root, + sink, + dartPackageName: DEFAULT_PACKAGE_NAME, + ); + final code = sink.toString(); + expect(code, contains('bool operator ==(Object other) {')); + expect(code, contains('int get hashCode =>')); + }); } diff --git a/packages/pigeon/test/gobject_generator_test.dart b/packages/pigeon/test/gobject_generator_test.dart index c9ef46a3aa43..8f44885a4617 100644 --- a/packages/pigeon/test/gobject_generator_test.dart +++ b/packages/pigeon/test/gobject_generator_test.dart @@ -1035,4 +1035,50 @@ void main() { expect(code, contains('const int test_package_object_type_id = 131;')); } }); + + test('data classes handle equality and hashing', () { + final inputClass = Class( + name: 'Input', + fields: [ + NamedType( + type: const TypeDeclaration(baseName: 'String', isNullable: true), + name: 'input', + ), + NamedType( + type: const TypeDeclaration(baseName: 'double', isNullable: false), + name: 'someDouble', + ), + NamedType( + type: const TypeDeclaration(baseName: 'Uint8List', isNullable: false), + name: 'someBytes', + ), + ], + ); + final root = Root( + apis: [], + classes: [inputClass], + enums: [], + ); + { + final sink = StringBuffer(); + const generator = GObjectGenerator(); + final generatorOptions = OutputFileOptions( + fileType: FileType.source, + languageOptions: const InternalGObjectOptions( + headerIncludePath: '', + gobjectHeaderOut: '', + gobjectSourceOut: '', + ), + ); + generator.generate( + generatorOptions, + root, + sink, + dartPackageName: DEFAULT_PACKAGE_NAME, + ); + final code = sink.toString(); + expect(code, contains('gboolean test_package_input_equals(')); + expect(code, contains('guint test_package_input_hash(')); + } + }); } diff --git a/packages/pigeon/test/java_generator_test.dart b/packages/pigeon/test/java_generator_test.dart index 777dd4755e57..a5f0708abf58 100644 --- a/packages/pigeon/test/java_generator_test.dart +++ b/packages/pigeon/test/java_generator_test.dart @@ -1891,4 +1891,33 @@ void main() { ), ); }); + + test('data class equality', () { + final classDefinition = Class( + name: 'Foobar', + fields: [ + NamedType( + type: const TypeDeclaration(baseName: 'int', isNullable: true), + name: 'field1', + ), + ], + ); + final root = Root( + apis: [], + classes: [classDefinition], + enums: [], + ); + final sink = StringBuffer(); + const javaOptions = InternalJavaOptions(className: 'Messages', javaOut: ''); + const generator = JavaGenerator(); + generator.generate( + javaOptions, + root, + sink, + dartPackageName: DEFAULT_PACKAGE_NAME, + ); + final code = sink.toString(); + expect(code, contains('public boolean equals(Object o) {')); + expect(code, contains('public int hashCode() {')); + }); } diff --git a/packages/pigeon/test/kotlin_generator_test.dart b/packages/pigeon/test/kotlin_generator_test.dart index 1de8ae95e8ae..479357d57fe3 100644 --- a/packages/pigeon/test/kotlin_generator_test.dart +++ b/packages/pigeon/test/kotlin_generator_test.dart @@ -2070,4 +2070,66 @@ void main() { // There should be only one occurrence of 'is Foo' in the block expect(count, 1); }); + + test('data class equality', () { + final classDefinition = Class( + name: 'Foobar', + fields: [ + NamedType( + type: const TypeDeclaration(baseName: 'int', isNullable: true), + name: 'field1', + ), + ], + ); + final root = Root( + apis: [], + classes: [classDefinition], + enums: [], + ); + final sink = StringBuffer(); + const kotlinOptions = InternalKotlinOptions(kotlinOut: ''); + const generator = KotlinGenerator(); + generator.generate( + kotlinOptions, + root, + sink, + dartPackageName: DEFAULT_PACKAGE_NAME, + ); + final code = sink.toString(); + expect(code, contains('override fun equals(other: Any?): Boolean {')); + expect(code, contains('override fun hashCode(): Int {')); + }); + + test('data class equality multi-field', () { + final classDefinition = Class( + name: 'Foobar', + fields: [ + NamedType( + type: const TypeDeclaration(baseName: 'int', isNullable: true), + name: 'field1', + ), + NamedType( + type: const TypeDeclaration(baseName: 'String', isNullable: true), + name: 'field2', + ), + ], + ); + final root = Root( + apis: [], + classes: [classDefinition], + enums: [], + ); + final sink = StringBuffer(); + const kotlinOptions = InternalKotlinOptions(kotlinOut: ''); + const generator = KotlinGenerator(); + generator.generate( + kotlinOptions, + root, + sink, + dartPackageName: DEFAULT_PACKAGE_NAME, + ); + final code = sink.toString(); + expect(code, contains('override fun equals(other: Any?): Boolean {')); + expect(code, contains('override fun hashCode(): Int {')); + }); } diff --git a/packages/pigeon/test/objc_generator_test.dart b/packages/pigeon/test/objc_generator_test.dart index b44f84f571d3..fb18833f77bc 100644 --- a/packages/pigeon/test/objc_generator_test.dart +++ b/packages/pigeon/test/objc_generator_test.dart @@ -4040,4 +4040,63 @@ void main() { expect(code, isNot(contains('FLTFLT'))); expect(code, contains('FLTEnum1Box')); }); + + test('data class equality', () { + final root = Root( + apis: [], + classes: [ + Class( + name: 'Foo', + fields: [ + NamedType( + type: const TypeDeclaration(baseName: 'int', isNullable: false), + name: 'bar', + ), + ], + ), + ], + enums: [], + ); + { + final sink = StringBuffer(); + const generator = ObjcGenerator(); + final generatorOptions = OutputFileOptions( + fileType: FileType.header, + languageOptions: const InternalObjcOptions( + prefix: 'ABC', + objcHeaderOut: '', + objcSourceOut: '', + headerIncludePath: '', + ), + ); + generator.generate( + generatorOptions, + root, + sink, + dartPackageName: DEFAULT_PACKAGE_NAME, + ); + } + { + final sink = StringBuffer(); + const generator = ObjcGenerator(); + final generatorOptions = OutputFileOptions( + fileType: FileType.source, + languageOptions: const InternalObjcOptions( + prefix: 'ABC', + objcHeaderOut: '', + objcSourceOut: '', + headerIncludePath: '', + ), + ); + generator.generate( + generatorOptions, + root, + sink, + dartPackageName: DEFAULT_PACKAGE_NAME, + ); + final code = sink.toString(); + expect(code, contains('- (BOOL)isEqual:(id)object {')); + expect(code, contains('- (NSUInteger)hash {')); + } + }); } diff --git a/packages/pigeon/test/swift_generator_test.dart b/packages/pigeon/test/swift_generator_test.dart index c91f09e9976b..fa567e2b02c8 100644 --- a/packages/pigeon/test/swift_generator_test.dart +++ b/packages/pigeon/test/swift_generator_test.dart @@ -1785,4 +1785,72 @@ void main() { ), ); }); + + test('data class equality', () { + final classDefinition = Class( + name: 'Foobar', + fields: [ + NamedType( + type: const TypeDeclaration(baseName: 'int', isNullable: true), + name: 'field1', + ), + ], + ); + final root = Root( + apis: [], + classes: [classDefinition], + enums: [], + ); + final sink = StringBuffer(); + const swiftOptions = InternalSwiftOptions(swiftOut: ''); + const generator = SwiftGenerator(); + generator.generate( + swiftOptions, + root, + sink, + dartPackageName: DEFAULT_PACKAGE_NAME, + ); + final code = sink.toString(); + expect( + code, + contains('static func == (lhs: Foobar, rhs: Foobar) -> Bool {'), + ); + expect(code, contains('func hash(into hasher: inout Hasher) {')); + }); + + test('data class equality multi-field', () { + final classDefinition = Class( + name: 'Foobar', + fields: [ + NamedType( + type: const TypeDeclaration(baseName: 'int', isNullable: true), + name: 'field1', + ), + NamedType( + type: const TypeDeclaration(baseName: 'String', isNullable: true), + name: 'field2', + ), + ], + ); + final root = Root( + apis: [], + classes: [classDefinition], + enums: [], + ); + final sink = StringBuffer(); + const swiftOptions = InternalSwiftOptions(swiftOut: ''); + const generator = SwiftGenerator(); + generator.generate( + swiftOptions, + root, + sink, + dartPackageName: DEFAULT_PACKAGE_NAME, + ); + final code = sink.toString(); + expect( + code, + contains('static func == (lhs: Foobar, rhs: Foobar) -> Bool {'), + ); + expect(code, contains('func hash(into hasher: inout Hasher) {')); + }); } diff --git a/packages/quick_actions/quick_actions_android/CHANGELOG.md b/packages/quick_actions/quick_actions_android/CHANGELOG.md index 9fdf32001183..fcacbb356d3c 100644 --- a/packages/quick_actions/quick_actions_android/CHANGELOG.md +++ b/packages/quick_actions/quick_actions_android/CHANGELOG.md @@ -1,5 +1,6 @@ -## NEXT +## 1.0.28 +* Updates build files from Groovy to Kotlin. * Updates minimum supported SDK version to Flutter 3.35/Dart 3.9. ## 1.0.27 diff --git a/packages/quick_actions/quick_actions_android/android/build.gradle b/packages/quick_actions/quick_actions_android/android/build.gradle.kts similarity index 64% rename from packages/quick_actions/quick_actions_android/android/build.gradle rename to packages/quick_actions/quick_actions_android/android/build.gradle.kts index 7b5ee57fec5d..bb8fa232e967 100644 --- a/packages/quick_actions/quick_actions_android/android/build.gradle +++ b/packages/quick_actions/quick_actions_android/android/build.gradle.kts @@ -12,14 +12,16 @@ buildscript { } } -rootProject.allprojects { +allprojects { repositories { google() mavenCentral() } } -apply plugin: 'com.android.library' +plugins { + id("com.android.library") +} android { namespace = "io.flutter.plugins.quickactions" @@ -33,7 +35,7 @@ android { lint { checkAllWarnings = true warningsAsErrors = true - disable 'AndroidGradlePluginVersion', 'InvalidPackage', 'GradleDependency', 'NewerVersionAvailable' + disable.addAll(setOf("AndroidGradlePluginVersion", "InvalidPackage", "GradleDependency", "NewerVersionAvailable")) } dependencies { @@ -48,13 +50,15 @@ android { } testOptions { - unitTests.includeAndroidResources = true - unitTests.returnDefaultValues = true - unitTests.all { - testLogging { - events "passed", "skipped", "failed", "standardOut", "standardError" - outputs.upToDateWhen {false} - showStandardStreams = true + unitTests { + isIncludeAndroidResources = true + isReturnDefaultValues = true + all { + it.outputs.upToDateWhen { false } + it.testLogging { + events("passed", "skipped", "failed", "standardOut", "standardError") + showStandardStreams = true + } } } } diff --git a/packages/quick_actions/quick_actions_android/android/settings.gradle b/packages/quick_actions/quick_actions_android/android/settings.gradle deleted file mode 100644 index 75248241ec35..000000000000 --- a/packages/quick_actions/quick_actions_android/android/settings.gradle +++ /dev/null @@ -1 +0,0 @@ -rootProject.name = 'quick_actions' diff --git a/packages/quick_actions/quick_actions_android/android/settings.gradle.kts b/packages/quick_actions/quick_actions_android/android/settings.gradle.kts new file mode 100644 index 000000000000..300d89d29631 --- /dev/null +++ b/packages/quick_actions/quick_actions_android/android/settings.gradle.kts @@ -0,0 +1 @@ +rootProject.name = "quick_actions" diff --git a/packages/quick_actions/quick_actions_android/pubspec.yaml b/packages/quick_actions/quick_actions_android/pubspec.yaml index d468da6bbd51..dd05368fd9de 100644 --- a/packages/quick_actions/quick_actions_android/pubspec.yaml +++ b/packages/quick_actions/quick_actions_android/pubspec.yaml @@ -2,7 +2,7 @@ name: quick_actions_android description: An implementation for the Android platform of the Flutter `quick_actions` plugin. repository: https://github.com/flutter/packages/tree/main/packages/quick_actions/quick_actions_android issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+in_app_purchase%22 -version: 1.0.27 +version: 1.0.28 environment: sdk: ^3.9.0 diff --git a/packages/quick_actions/quick_actions_ios/CHANGELOG.md b/packages/quick_actions/quick_actions_ios/CHANGELOG.md index 506580fd211c..4f1cbc7cf8eb 100644 --- a/packages/quick_actions/quick_actions_ios/CHANGELOG.md +++ b/packages/quick_actions/quick_actions_ios/CHANGELOG.md @@ -1,3 +1,8 @@ +## 1.2.4 + +* Adds support for UIScene lifecycle. +* Updates minimum supported SDK version to Flutter 3.38/Dart 3.10. + ## 1.2.3 * Updates to Pigeon 26. diff --git a/packages/quick_actions/quick_actions_ios/example/ios/Runner/AppDelegate.swift b/packages/quick_actions/quick_actions_ios/example/ios/Runner/AppDelegate.swift index 6fa401143d5a..b5bc5f9682ba 100644 --- a/packages/quick_actions/quick_actions_ios/example/ios/Runner/AppDelegate.swift +++ b/packages/quick_actions/quick_actions_ios/example/ios/Runner/AppDelegate.swift @@ -6,14 +6,17 @@ import Flutter import UIKit @main -@objc class AppDelegate: FlutterAppDelegate { +@objc class AppDelegate: FlutterAppDelegate, FlutterImplicitEngineDelegate { override func application( _ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? ) -> Bool { - GeneratedPluginRegistrant.register(with: self) super.application(application, didFinishLaunchingWithOptions: launchOptions) // For UI integration tests. See https://github.com/flutter/plugins/pull/3811. return false } + + func didInitializeImplicitFlutterEngine(_ engineBridge: FlutterImplicitEngineBridge) { + GeneratedPluginRegistrant.register(with: engineBridge.pluginRegistry) + } } diff --git a/packages/quick_actions/quick_actions_ios/example/ios/Runner/Info.plist b/packages/quick_actions/quick_actions_ios/example/ios/Runner/Info.plist index fd3b62987824..7fba3010b0d8 100644 --- a/packages/quick_actions/quick_actions_ios/example/ios/Runner/Info.plist +++ b/packages/quick_actions/quick_actions_ios/example/ios/Runner/Info.plist @@ -45,5 +45,26 @@ UIApplicationSupportsIndirectInputEvents + UIApplicationSceneManifest + + UIApplicationSupportsMultipleScenes + + UISceneConfigurations + + UIWindowSceneSessionRoleApplication + + + UISceneClassName + UIWindowScene + UISceneDelegateClassName + FlutterSceneDelegate + UISceneConfigurationName + flutter + UISceneStoryboardFile + Main + + + + diff --git a/packages/quick_actions/quick_actions_ios/example/ios/RunnerTests/QuickActionsPluginTests.swift b/packages/quick_actions/quick_actions_ios/example/ios/RunnerTests/QuickActionsPluginTests.swift index 98766194b3bc..ad2f043af105 100644 --- a/packages/quick_actions/quick_actions_ios/example/ios/RunnerTests/QuickActionsPluginTests.swift +++ b/packages/quick_actions/quick_actions_ios/example/ios/RunnerTests/QuickActionsPluginTests.swift @@ -223,4 +223,108 @@ struct QuickActionsPluginTests { plugin.applicationDidBecomeActive(UIApplication.shared) } } + + // MARK: - Scene lifecycle tests + + @Test func windowScenePerformActionForShortcutItem() async { + let flutterApi: MockFlutterApi = MockFlutterApi() + let mockShortcutItemProvider = MockShortcutItemProvider() + + let plugin = QuickActionsPlugin( + flutterApi: flutterApi, + shortcutItemProvider: mockShortcutItemProvider) + + let item = UIApplicationShortcutItem( + type: "SearchTheThing", + localizedTitle: "Search the thing", + localizedSubtitle: nil, + icon: UIApplicationShortcutIcon(templateImageName: "search_the_thing.png"), + userInfo: nil) + + await confirmation("shortcut should be handled via windowScene") { confirmed in + flutterApi.launchActionCallback = { aString in + #expect(aString == item.type) + confirmed() + } + + let windowScene = UIApplication.shared.connectedScenes.first as! UIWindowScene + var completionSuccess: Bool? + let actionResult = plugin.windowScene( + windowScene, + performActionFor: item + ) { success in + completionSuccess = success + } + + #expect(actionResult, "windowScene performActionFor must return true.") + #expect(completionSuccess == true) + } + } + + @Test func sceneWillConnectToWithoutShortcut() { + let flutterApi: MockFlutterApi = MockFlutterApi() + let mockShortcutItemProvider = MockShortcutItemProvider() + + let plugin = QuickActionsPlugin( + flutterApi: flutterApi, + shortcutItemProvider: mockShortcutItemProvider) + + let connectResult = plugin.scene( + UIApplication.shared.connectedScenes.first!, + willConnectTo: UIApplication.shared.connectedScenes.first!.session, + options: nil) + #expect( + !connectResult, + "scene willConnectTo must return false if not launched from shortcut.") + } + + @Test func sceneDidBecomeActiveLaunchWithoutShortcut() async { + let flutterApi: MockFlutterApi = MockFlutterApi() + let mockShortcutItemProvider = MockShortcutItemProvider() + + let plugin = QuickActionsPlugin( + flutterApi: flutterApi, + shortcutItemProvider: mockShortcutItemProvider) + + let connectResult = plugin.scene( + UIApplication.shared.connectedScenes.first!, + willConnectTo: UIApplication.shared.connectedScenes.first!.session, + options: nil) + #expect(!connectResult) + + await confirmation("launchAction should not be called", expectedCount: 0) { confirmed in + flutterApi.launchActionCallback = { _ in + confirmed() + } + plugin.sceneDidBecomeActive(UIApplication.shared.connectedScenes.first!) + } + } + + @Test func sceneDidBecomeActiveLaunchWithShortcut() async { + let item = UIApplicationShortcutItem( + type: "SearchTheThing", + localizedTitle: "Search the thing", + localizedSubtitle: nil, + icon: UIApplicationShortcutIcon(templateImageName: "search_the_thing.png"), + userInfo: nil) + + let flutterApi: MockFlutterApi = MockFlutterApi() + let mockShortcutItemProvider = MockShortcutItemProvider() + + let plugin = QuickActionsPlugin( + flutterApi: flutterApi, + shortcutItemProvider: mockShortcutItemProvider) + + await confirmation("shortcut should be handled when scene becomes active") { confirmed in + flutterApi.launchActionCallback = { aString in + #expect(aString == item.type) + confirmed() + } + + let connectResult = plugin.handleSceneWillConnectTo(shortcutItem: item) + #expect(connectResult, "scene willConnectTo must return true when shortcut is provided.") + + plugin.sceneDidBecomeActive(UIApplication.shared.connectedScenes.first!) + } + } } diff --git a/packages/quick_actions/quick_actions_ios/example/pubspec.yaml b/packages/quick_actions/quick_actions_ios/example/pubspec.yaml index 8917f495bf01..46a29f8dc9ee 100644 --- a/packages/quick_actions/quick_actions_ios/example/pubspec.yaml +++ b/packages/quick_actions/quick_actions_ios/example/pubspec.yaml @@ -3,8 +3,8 @@ description: Demonstrates how to use the quick_actions plugin. publish_to: none environment: - sdk: ^3.9.0 - flutter: ">=3.35.0" + sdk: ^3.10.0 + flutter: ">=3.38.0" dependencies: flutter: diff --git a/packages/quick_actions/quick_actions_ios/ios/quick_actions_ios/Sources/quick_actions_ios/QuickActionsPlugin.swift b/packages/quick_actions/quick_actions_ios/ios/quick_actions_ios/Sources/quick_actions_ios/QuickActionsPlugin.swift index 3f2d91518a11..0ff0980c81d5 100644 --- a/packages/quick_actions/quick_actions_ios/ios/quick_actions_ios/Sources/quick_actions_ios/QuickActionsPlugin.swift +++ b/packages/quick_actions/quick_actions_ios/ios/quick_actions_ios/Sources/quick_actions_ios/QuickActionsPlugin.swift @@ -3,8 +3,11 @@ // found in the LICENSE file. import Flutter +import UIKit -public final class QuickActionsPlugin: NSObject, FlutterPlugin, IOSQuickActionsApi { +public final class QuickActionsPlugin: NSObject, FlutterPlugin, IOSQuickActionsApi, + FlutterSceneLifeCycleDelegate +{ public static func register(with registrar: FlutterPluginRegistrar) { let messenger = registrar.messenger() @@ -12,6 +15,7 @@ public final class QuickActionsPlugin: NSObject, FlutterPlugin, IOSQuickActionsA let instance = QuickActionsPlugin(flutterApi: flutterApi) IOSQuickActionsApiSetup.setUp(binaryMessenger: messenger, api: instance) registrar.addApplicationDelegate(instance) + registrar.addSceneDelegate(instance) } private let shortcutItemProvider: ShortcutItemProviding @@ -72,6 +76,46 @@ public final class QuickActionsPlugin: NSObject, FlutterPlugin, IOSQuickActionsA } } + // MARK: - FlutterSceneLifeCycleDelegate + + public func scene( + _ scene: UIScene, + willConnectTo session: UISceneSession, + options connectionOptions: UIScene.ConnectionOptions? + ) -> Bool { + return handleSceneWillConnectTo(shortcutItem: connectionOptions?.shortcutItem) + } + + func handleSceneWillConnectTo(shortcutItem: UIApplicationShortcutItem?) -> Bool { + if let shortcutItem { + // Keep hold of the shortcut type and handle it in the + // `sceneDidBecomeActive:` method once the Dart MethodChannel + // is initialized. + launchingShortcutType = shortcutItem.type + return true + } + return false + } + + public func sceneDidBecomeActive(_ scene: UIScene) { + if let shortcutType = launchingShortcutType { + handleShortcut(shortcutType) + launchingShortcutType = nil + } + } + + public func windowScene( + _ windowScene: UIWindowScene, + performActionFor shortcutItem: UIApplicationShortcutItem, + completionHandler: @escaping (Bool) -> Void + ) -> Bool { + handleShortcut(shortcutItem.type) + completionHandler(true) + return true + } + + // MARK: - Shortcut handling + func handleShortcut(_ shortcut: String) { flutterApi.launchAction(action: shortcut) { _ in // noop diff --git a/packages/quick_actions/quick_actions_ios/pubspec.yaml b/packages/quick_actions/quick_actions_ios/pubspec.yaml index 478edffea6ea..e1f48024ccf0 100644 --- a/packages/quick_actions/quick_actions_ios/pubspec.yaml +++ b/packages/quick_actions/quick_actions_ios/pubspec.yaml @@ -2,11 +2,11 @@ name: quick_actions_ios description: An implementation for the iOS platform of the Flutter `quick_actions` plugin. repository: https://github.com/flutter/packages/tree/main/packages/quick_actions/quick_actions_ios issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+in_app_purchase%22 -version: 1.2.3 +version: 1.2.4 environment: - sdk: ^3.9.0 - flutter: ">=3.35.0" + sdk: ^3.10.0 + flutter: ">=3.38.0" flutter: plugin: diff --git a/packages/rfw/CHANGELOG.md b/packages/rfw/CHANGELOG.md index f9538956d3c9..2aa690d15f0e 100644 --- a/packages/rfw/CHANGELOG.md +++ b/packages/rfw/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.1.3 + +* Fixes dartdoc comments that accidentally used HTML. + ## 1.1.2 * Removes outdated call for feedback from the README. diff --git a/packages/rfw/lib/src/flutter/argument_decoders.dart b/packages/rfw/lib/src/flutter/argument_decoders.dart index b40702fc7d23..8da61794e49c 100644 --- a/packages/rfw/lib/src/flutter/argument_decoders.dart +++ b/packages/rfw/lib/src/flutter/argument_decoders.dart @@ -614,8 +614,9 @@ class ArgumentDecoders { /// The first argument must be the `values` list for that enum; this is the /// list of values that is searched. /// - /// For example, `enumValue(TileMode.values, source, ['tileMode']) ?? - /// TileMode.clamp` reads the `tileMode` key of `source`, and looks for the + /// For example, + /// `enumValue(TileMode.values, source, ['tileMode']) ?? TileMode.clamp` + /// reads the `tileMode` key of `source`, and looks for the /// first match in [TileMode.values], defaulting to [TileMode.clamp] if /// nothing matches; thus, the string `mirror` would return [TileMode.mirror]. static T? enumValue(List values, DataSource source, List key) { diff --git a/packages/rfw/pubspec.yaml b/packages/rfw/pubspec.yaml index 72341a9f8462..f4233d22e326 100644 --- a/packages/rfw/pubspec.yaml +++ b/packages/rfw/pubspec.yaml @@ -2,7 +2,7 @@ name: rfw description: "Remote Flutter widgets: a library for rendering declarative widget description files at runtime." repository: https://github.com/flutter/packages/tree/main/packages/rfw issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+rfw%22 -version: 1.1.2 +version: 1.1.3 environment: sdk: ^3.9.0 diff --git a/packages/shared_preferences/shared_preferences/CHANGELOG.md b/packages/shared_preferences/shared_preferences/CHANGELOG.md index 5cf4a09e2cbe..07f50a0778dd 100644 --- a/packages/shared_preferences/shared_preferences/CHANGELOG.md +++ b/packages/shared_preferences/shared_preferences/CHANGELOG.md @@ -1,3 +1,7 @@ +## 2.5.5 + +* Fixes dartdoc comments that accidentally used HTML. + ## 2.5.4 * Updates dependencies for the `shared_preferences_tool` DevTools extension and fixes related deprecations. diff --git a/packages/shared_preferences/shared_preferences/lib/src/shared_preferences_async.dart b/packages/shared_preferences/shared_preferences/lib/src/shared_preferences_async.dart index d6d9e326708f..5fd079d7a963 100644 --- a/packages/shared_preferences/shared_preferences/lib/src/shared_preferences_async.dart +++ b/packages/shared_preferences/shared_preferences/lib/src/shared_preferences_async.dart @@ -61,31 +61,31 @@ class SharedPreferencesAsync { } /// Reads a value from the platform, throwing a [TypeError] if the value is - /// not a bool. + /// not a `bool`. Future getBool(String key) async { return _platform.getBool(key, _options); } /// Reads a value from the platform, throwing a [TypeError] if the value is - /// not an int. + /// not an `int`. Future getInt(String key) async { return _platform.getInt(key, _options); } /// Reads a value from the platform, throwing a [TypeError] if the value is - /// not a double. + /// not a `double`. Future getDouble(String key) async { return _platform.getDouble(key, _options); } /// Reads a value from the platform, throwing a [TypeError] if the value is - /// not a String. + /// not a `String`. Future getString(String key) async { return _platform.getString(key, _options); } /// Reads a list of string values from the platform, throwing a [TypeError] - /// if the value not a List. + /// if the value is not a `List`. Future?> getStringList(String key) async { return _platform.getStringList(key, _options); } diff --git a/packages/shared_preferences/shared_preferences/pubspec.yaml b/packages/shared_preferences/shared_preferences/pubspec.yaml index d3c8a52238ff..ef4ffbc6d62d 100644 --- a/packages/shared_preferences/shared_preferences/pubspec.yaml +++ b/packages/shared_preferences/shared_preferences/pubspec.yaml @@ -3,7 +3,7 @@ description: Flutter plugin for reading and writing simple key-value pairs. Wraps NSUserDefaults on iOS and SharedPreferences on Android. repository: https://github.com/flutter/packages/tree/main/packages/shared_preferences/shared_preferences issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+shared_preferences%22 -version: 2.5.4 +version: 2.5.5 environment: sdk: ^3.9.0 diff --git a/packages/shared_preferences/shared_preferences_android/CHANGELOG.md b/packages/shared_preferences/shared_preferences_android/CHANGELOG.md index d9d83230286a..117b363132d6 100644 --- a/packages/shared_preferences/shared_preferences_android/CHANGELOG.md +++ b/packages/shared_preferences/shared_preferences_android/CHANGELOG.md @@ -1,3 +1,11 @@ +## 2.4.23 + +* Fixes dartdoc comments that accidentally used HTML. + +## 2.4.22 + +* Updates build files from Groovy to Kotlin. + ## 2.4.21 * Reverts `androidx.datastore:datastore` to 1.1.7 due to a regression 16 KB diff --git a/packages/shared_preferences/shared_preferences_android/android/build.gradle b/packages/shared_preferences/shared_preferences_android/android/build.gradle.kts similarity index 61% rename from packages/shared_preferences/shared_preferences_android/android/build.gradle rename to packages/shared_preferences/shared_preferences_android/android/build.gradle.kts index 98f49676199a..edf15edc0ca4 100644 --- a/packages/shared_preferences/shared_preferences_android/android/build.gradle +++ b/packages/shared_preferences/shared_preferences_android/android/build.gradle.kts @@ -1,8 +1,10 @@ +import org.jetbrains.kotlin.gradle.dsl.JvmTarget + group = "io.flutter.plugins.sharedpreferences" version = "1.0-SNAPSHOT" buildscript { - ext.kotlin_version = '2.3.0' + val kotlinVersion = "2.3.0" repositories { google() mavenCentral() @@ -10,27 +12,33 @@ buildscript { dependencies { classpath("com.android.tools.build:gradle:8.13.1") - classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version") + classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion") } } -rootProject.allprojects { +allprojects { repositories { google() mavenCentral() } } -allprojects { - gradle.projectsEvaluated { - tasks.withType(JavaCompile) { - options.compilerArgs << "-Xlint:unchecked" << "-Xlint:deprecation" - } - } +// TODO(stuartmorgan): See if this can be removed. +tasks.withType().configureEach { + options.compilerArgs.add("-Xlint:deprecation") + options.compilerArgs.add("-Xlint:unchecked") } -apply plugin: 'com.android.library' -apply plugin: 'kotlin-android' +plugins { + id("com.android.library") + id("kotlin-android") +} + +kotlin { + compilerOptions { + jvmTarget = JvmTarget.fromTarget(JavaVersion.VERSION_17.toString()) + } +} android { namespace = "io.flutter.plugins.sharedpreferences" @@ -41,14 +49,6 @@ android { targetCompatibility = JavaVersion.VERSION_17 } - kotlinOptions { - jvmTarget = JavaVersion.VERSION_17.toString() - } - - sourceSets { - main.java.srcDirs += 'src/main/kotlin' - } - defaultConfig { minSdk = 24 testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" @@ -57,7 +57,7 @@ android { lint { checkAllWarnings = true warningsAsErrors = true - disable 'AndroidGradlePluginVersion', 'InvalidPackage', 'GradleDependency', 'NewerVersionAvailable' + disable.addAll(setOf("AndroidGradlePluginVersion", "InvalidPackage", "GradleDependency", "NewerVersionAvailable")) baseline = file("lint-baseline.xml") } @@ -74,13 +74,15 @@ android { } testOptions { - unitTests.includeAndroidResources = true - unitTests.returnDefaultValues = true - unitTests.all { - testLogging { - events "passed", "skipped", "failed", "standardOut", "standardError" - outputs.upToDateWhen {false} - showStandardStreams = true + unitTests { + isIncludeAndroidResources = true + isReturnDefaultValues = true + all { + it.outputs.upToDateWhen { false } + it.testLogging { + events("passed", "skipped", "failed", "standardOut", "standardError") + showStandardStreams = true + } } } } diff --git a/packages/shared_preferences/shared_preferences_android/android/settings.gradle b/packages/shared_preferences/shared_preferences_android/android/settings.gradle deleted file mode 100644 index 033d5be261a7..000000000000 --- a/packages/shared_preferences/shared_preferences_android/android/settings.gradle +++ /dev/null @@ -1 +0,0 @@ -rootProject.name = 'shared_preferences_android' diff --git a/packages/shared_preferences/shared_preferences_android/android/settings.gradle.kts b/packages/shared_preferences/shared_preferences_android/android/settings.gradle.kts new file mode 100644 index 000000000000..e526d4c93d44 --- /dev/null +++ b/packages/shared_preferences/shared_preferences_android/android/settings.gradle.kts @@ -0,0 +1 @@ +rootProject.name = "shared_preferences_android" diff --git a/packages/shared_preferences/shared_preferences_android/pigeons/messages.dart b/packages/shared_preferences/shared_preferences_android/pigeons/messages.dart index c42810f609f4..282e1b547aab 100644 --- a/packages/shared_preferences/shared_preferences_android/pigeons/messages.dart +++ b/packages/shared_preferences/shared_preferences_android/pigeons/messages.dart @@ -23,27 +23,27 @@ abstract class SharedPreferencesApi { @TaskQueue(type: TaskQueueType.serialBackgroundThread) bool remove(String key); - /// Adds property to shared preferences data set of type bool. + /// Adds property to shared preferences data set of type `bool`. @TaskQueue(type: TaskQueueType.serialBackgroundThread) bool setBool(String key, bool value); - /// Adds property to shared preferences data set of type String. + /// Adds property to shared preferences data set of type `String`. @TaskQueue(type: TaskQueueType.serialBackgroundThread) bool setString(String key, String value); - /// Adds property to shared preferences data set of type int. + /// Adds property to shared preferences data set of type `int`. @TaskQueue(type: TaskQueueType.serialBackgroundThread) bool setInt(String key, int value); - /// Adds property to shared preferences data set of type double. + /// Adds property to shared preferences data set of type `double`. @TaskQueue(type: TaskQueueType.serialBackgroundThread) bool setDouble(String key, double value); - /// Adds property to shared preferences data set of type List. + /// Adds property to shared preferences data set of type `List`. @TaskQueue(type: TaskQueueType.serialBackgroundThread) bool setEncodedStringList(String key, String value); - /// Adds property to shared preferences data set of type List. + /// Adds property to shared preferences data set of type `List`. /// /// Deprecated, this is only here for testing purposes. @TaskQueue(type: TaskQueueType.serialBackgroundThread) diff --git a/packages/shared_preferences/shared_preferences_android/pigeons/messages_async.dart b/packages/shared_preferences/shared_preferences_android/pigeons/messages_async.dart index 9b32c0c2a1dc..a0b0ec0b8ed1 100644 --- a/packages/shared_preferences/shared_preferences_android/pigeons/messages_async.dart +++ b/packages/shared_preferences/shared_preferences_android/pigeons/messages_async.dart @@ -50,11 +50,11 @@ class StringListResult { @HostApi() abstract class SharedPreferencesAsyncApi { - /// Adds property to shared preferences data set of type bool. + /// Adds property to shared preferences data set of type `bool`. @TaskQueue(type: TaskQueueType.serialBackgroundThread) void setBool(String key, bool value, SharedPreferencesPigeonOptions options); - /// Adds property to shared preferences data set of type String. + /// Adds property to shared preferences data set of type `String`. @TaskQueue(type: TaskQueueType.serialBackgroundThread) void setString( String key, @@ -62,11 +62,11 @@ abstract class SharedPreferencesAsyncApi { SharedPreferencesPigeonOptions options, ); - /// Adds property to shared preferences data set of type int. + /// Adds property to shared preferences data set of type `int`. @TaskQueue(type: TaskQueueType.serialBackgroundThread) void setInt(String key, int value, SharedPreferencesPigeonOptions options); - /// Adds property to shared preferences data set of type double. + /// Adds property to shared preferences data set of type `double`. @TaskQueue(type: TaskQueueType.serialBackgroundThread) void setDouble( String key, @@ -74,7 +74,7 @@ abstract class SharedPreferencesAsyncApi { SharedPreferencesPigeonOptions options, ); - /// Adds property to shared preferences data set of type List. + /// Adds property to shared preferences data set of type `List`. @TaskQueue(type: TaskQueueType.serialBackgroundThread) void setEncodedStringList( String key, @@ -82,7 +82,7 @@ abstract class SharedPreferencesAsyncApi { SharedPreferencesPigeonOptions options, ); - /// Adds property to shared preferences data set of type List. + /// Adds property to shared preferences data set of type `List`. /// /// Deprecated, this is only here for testing purposes. @TaskQueue(type: TaskQueueType.serialBackgroundThread) @@ -108,14 +108,14 @@ abstract class SharedPreferencesAsyncApi { @TaskQueue(type: TaskQueueType.serialBackgroundThread) int? getInt(String key, SharedPreferencesPigeonOptions options); - /// Gets individual List value stored with [key], if any. + /// Gets individual `List` value stored with [key], if any. @TaskQueue(type: TaskQueueType.serialBackgroundThread) List? getPlatformEncodedStringList( String key, SharedPreferencesPigeonOptions options, ); - /// Gets the JSON-encoded List value stored with [key], if any. + /// Gets the JSON-encoded `List` value stored with [key], if any. @TaskQueue(type: TaskQueueType.serialBackgroundThread) StringListResult? getStringList( String key, diff --git a/packages/shared_preferences/shared_preferences_android/pubspec.yaml b/packages/shared_preferences/shared_preferences_android/pubspec.yaml index 8ef265cd3b95..93d6a4dcbcf1 100644 --- a/packages/shared_preferences/shared_preferences_android/pubspec.yaml +++ b/packages/shared_preferences/shared_preferences_android/pubspec.yaml @@ -2,7 +2,7 @@ name: shared_preferences_android description: Android implementation of the shared_preferences plugin repository: https://github.com/flutter/packages/tree/main/packages/shared_preferences/shared_preferences_android issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+shared_preferences%22 -version: 2.4.21 +version: 2.4.23 environment: sdk: ^3.9.0 diff --git a/packages/shared_preferences/shared_preferences_platform_interface/CHANGELOG.md b/packages/shared_preferences/shared_preferences_platform_interface/CHANGELOG.md index 49dd411c6dbb..b986626e8f9e 100644 --- a/packages/shared_preferences/shared_preferences_platform_interface/CHANGELOG.md +++ b/packages/shared_preferences/shared_preferences_platform_interface/CHANGELOG.md @@ -1,5 +1,6 @@ -## NEXT +## 2.4.2 +* Fixes dartdoc comments that accidentally used HTML. * Updates minimum supported SDK version to Flutter 3.35/Dart 3.9. ## 2.4.1 diff --git a/packages/shared_preferences/shared_preferences_platform_interface/lib/shared_preferences_async_platform_interface.dart b/packages/shared_preferences/shared_preferences_platform_interface/lib/shared_preferences_async_platform_interface.dart index f86e69dfd3aa..77dec7f04d10 100644 --- a/packages/shared_preferences/shared_preferences_platform_interface/lib/shared_preferences_async_platform_interface.dart +++ b/packages/shared_preferences/shared_preferences_platform_interface/lib/shared_preferences_async_platform_interface.dart @@ -38,40 +38,40 @@ abstract base class SharedPreferencesAsyncPlatform { /// Stores the int [value] associated with the [key]. Future setInt(String key, int value, SharedPreferencesOptions options); - /// Stores the List [value] associated with the [key]. + /// Stores the `List` [value] associated with the [key]. Future setStringList( String key, List value, SharedPreferencesOptions options, ); - /// Retrieves the String [value] associated with the [key], if any. + /// Retrieves the `String` [value] associated with the [key], if any. /// /// Throws a [TypeError] if the returned type is not a String. /// May return null for unsupported types. Future getString(String key, SharedPreferencesOptions options); - /// Retrieves the bool [value] associated with the [key], if any. + /// Retrieves the `bool` [value] associated with the [key], if any. /// /// Throws a [TypeError] if the returned type is not a bool. /// May return null for unsupported types. Future getBool(String key, SharedPreferencesOptions options); - /// Retrieves the double [value] associated with the [key], if any. + /// Retrieves the `double` [value] associated with the [key], if any. /// /// Throws a [TypeError] if the returned type is not a double. /// May return null for unsupported types. Future getDouble(String key, SharedPreferencesOptions options); - /// Retrieves the int [value] associated with the [key], if any. + /// Retrieves the `int` [value] associated with the [key], if any. /// /// Throws a [TypeError] if the returned type is not an int. /// May return null for unsupported types. Future getInt(String key, SharedPreferencesOptions options); - /// Retrieves the List [value] associated with the [key], if any. + /// Retrieves the `List` [value] associated with the [key], if any. /// - /// Throws a [TypeError] if the returned type is not a List. + /// Throws a [TypeError] if the returned type is not a `List`. /// May return null for unsupported types. Future?> getStringList( String key, diff --git a/packages/shared_preferences/shared_preferences_platform_interface/pubspec.yaml b/packages/shared_preferences/shared_preferences_platform_interface/pubspec.yaml index c1156c115374..5d470626f56a 100644 --- a/packages/shared_preferences/shared_preferences_platform_interface/pubspec.yaml +++ b/packages/shared_preferences/shared_preferences_platform_interface/pubspec.yaml @@ -2,7 +2,7 @@ name: shared_preferences_platform_interface description: A common platform interface for the shared_preferences plugin. repository: https://github.com/flutter/packages/tree/main/packages/shared_preferences/shared_preferences_platform_interface issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+shared_preferences%22 -version: 2.4.1 +version: 2.4.2 environment: sdk: ^3.9.0 diff --git a/packages/two_dimensional_scrollables/CHANGELOG.md b/packages/two_dimensional_scrollables/CHANGELOG.md index a201be420b1f..2f031898ab46 100644 --- a/packages/two_dimensional_scrollables/CHANGELOG.md +++ b/packages/two_dimensional_scrollables/CHANGELOG.md @@ -1,3 +1,15 @@ +## 0.4.1 + +* Adds warnings for TableView pinned rows and columns that exceed the viewport dimensions. + +## 0.4.0 + +* Added `alignment` property to `TableView` and `TreeView` to align content within the viewport when it is smaller than the viewport extent. + +## 0.3.9 + +* Fixes TableSpan borders being flipped when one or both axis directions are reversed. + ## 0.3.8 * Updates minimum supported SDK version to Flutter 3.35/Dart 3.9. diff --git a/packages/two_dimensional_scrollables/lib/src/common/span.dart b/packages/two_dimensional_scrollables/lib/src/common/span.dart index 27e40b4ae7e4..84d6f64da9ed 100644 --- a/packages/two_dimensional_scrollables/lib/src/common/span.dart +++ b/packages/two_dimensional_scrollables/lib/src/common/span.dart @@ -439,17 +439,24 @@ class SpanBorder { /// cells. void paint(SpanDecorationPaintDetails details, BorderRadius? borderRadius) { final AxisDirection axisDirection = details.axisDirection; + final AxisDirection? crossAxisDirection = details.crossAxisDirection; switch (axisDirectionToAxis(axisDirection)) { case Axis.horizontal: + final bool isLeadingTop = + crossAxisDirection == null || + crossAxisDirection == AxisDirection.down; final border = Border( - top: axisDirection == AxisDirection.right ? leading : trailing, - bottom: axisDirection == AxisDirection.right ? trailing : leading, + top: isLeadingTop ? leading : trailing, + bottom: isLeadingTop ? trailing : leading, ); border.paint(details.canvas, details.rect, borderRadius: borderRadius); case Axis.vertical: + final bool isLeadingLeft = + crossAxisDirection == null || + crossAxisDirection == AxisDirection.right; final border = Border( - left: axisDirection == AxisDirection.down ? leading : trailing, - right: axisDirection == AxisDirection.down ? trailing : leading, + left: isLeadingLeft ? leading : trailing, + right: isLeadingLeft ? trailing : leading, ); border.paint(details.canvas, details.rect, borderRadius: borderRadius); } @@ -468,6 +475,7 @@ class SpanDecorationPaintDetails { required this.canvas, required this.rect, required this.axisDirection, + this.crossAxisDirection, }); /// The [Canvas] that the [SpanDecoration] will be painted to. @@ -487,4 +495,10 @@ class SpanDecorationPaintDetails { /// [AxisDirection.right], which would be [Axis.horizontal], a row is being /// painted. final AxisDirection axisDirection; + + /// The [AxisDirection] of the [Axis] perpendicular to the [Span]. + /// + /// Used to determine the correct leading/trailing edge when deciding how to + /// paint borders or apply padding. + final AxisDirection? crossAxisDirection; } diff --git a/packages/two_dimensional_scrollables/lib/src/table_view/table.dart b/packages/two_dimensional_scrollables/lib/src/table_view/table.dart index 3f26dd00dfd3..b09a7898e852 100644 --- a/packages/two_dimensional_scrollables/lib/src/table_view/table.dart +++ b/packages/two_dimensional_scrollables/lib/src/table_view/table.dart @@ -116,6 +116,7 @@ class TableView extends TwoDimensionalScrollView { super.dragStartBehavior, super.keyboardDismissBehavior, super.clipBehavior, + this.alignment = Alignment.topLeft, }); /// Creates a [TableView] of widgets that are created on demand. @@ -155,6 +156,7 @@ class TableView extends TwoDimensionalScrollView { required TableSpanBuilder columnBuilder, required TableSpanBuilder rowBuilder, required TableViewCellBuilder cellBuilder, + this.alignment = Alignment.topLeft, }) : assert(pinnedRowCount >= 0), assert(rowCount == null || rowCount >= 0), assert(rowCount == null || rowCount >= pinnedRowCount), @@ -199,6 +201,7 @@ class TableView extends TwoDimensionalScrollView { required TableSpanBuilder columnBuilder, required TableSpanBuilder rowBuilder, List> cells = const >[], + this.alignment = Alignment.topLeft, }) : assert(pinnedRowCount >= 0), assert(pinnedColumnCount >= 0), super( @@ -211,6 +214,11 @@ class TableView extends TwoDimensionalScrollView { ), ); + /// The alignment of the table within the viewport when there is extra space. + /// + /// Defaults to [Alignment.topLeft]. + final AlignmentGeometry alignment; + @override TableViewport buildViewport( BuildContext context, @@ -226,6 +234,7 @@ class TableView extends TwoDimensionalScrollView { mainAxis: mainAxis, cacheExtent: cacheExtent, clipBehavior: clipBehavior, + alignment: alignment, ); } } @@ -245,8 +254,12 @@ class TableViewport extends TwoDimensionalViewport { required super.mainAxis, super.cacheExtent, super.clipBehavior, + this.alignment = Alignment.topLeft, }); + /// The alignment of the table within the viewport when there is extra space. + final AlignmentGeometry alignment; + @override RenderTwoDimensionalViewport createRenderObject(BuildContext context) { return RenderTableViewport( @@ -259,6 +272,8 @@ class TableViewport extends TwoDimensionalViewport { clipBehavior: clipBehavior, delegate: delegate as TableCellDelegateMixin, childManager: context as TwoDimensionalChildManager, + alignment: alignment, + textDirection: Directionality.maybeOf(context), ); } @@ -275,7 +290,9 @@ class TableViewport extends TwoDimensionalViewport { ..mainAxis = mainAxis ..cacheExtent = cacheExtent ..clipBehavior = clipBehavior - ..delegate = delegate as TableCellDelegateMixin; + ..delegate = delegate as TableCellDelegateMixin + ..alignment = alignment + ..textDirection = Directionality.maybeOf(context); } } @@ -299,7 +316,10 @@ class RenderTableViewport extends RenderTwoDimensionalViewport { required super.childManager, super.cacheExtent, super.clipBehavior, - }); + AlignmentGeometry alignment = Alignment.topLeft, + TextDirection? textDirection, + }) : _alignment = alignment, + _textDirection = textDirection; @override TableCellDelegateMixin get delegate => @@ -309,6 +329,31 @@ class RenderTableViewport extends RenderTwoDimensionalViewport { super.delegate = value; } + /// The alignment of the table within the viewport when there is extra space. + AlignmentGeometry get alignment => _alignment; + AlignmentGeometry _alignment; + set alignment(AlignmentGeometry value) { + if (_alignment == value) { + return; + } + _alignment = value; + markNeedsLayout(); + } + + /// The text direction with which to resolve [alignment]. + TextDirection? get textDirection => _textDirection; + TextDirection? _textDirection; + set textDirection(TextDirection? value) { + if (_textDirection == value) { + return; + } + _textDirection = value; + markNeedsLayout(); + } + + double _hAlignmentOffset = 0.0; + double _vAlignmentOffset = 0.0; + // Skipped vicinities for the current frame based on merged cells. // This prevents multiple build calls for the same cell that spans multiple // vicinities. @@ -384,13 +429,6 @@ class RenderTableViewport extends RenderTwoDimensionalViewport { ); } - // TODO(Piinks): Pinned rows/cols do not account for what is visible on the - // screen. Ostensibly, we would not want to have pinned rows/columns that - // extend beyond the viewport, we would never see them as they would never - // scroll into view. So this currently implementation is fairly assuming - // we will never have rows/cols that are outside of the viewport. We should - // maybe add an assertion for this during layout. - // https://github.com/flutter/flutter/issues/136833 int? get _lastPinnedRow => delegate.pinnedRowCount > 0 ? delegate.pinnedRowCount - 1 : null; int? get _lastPinnedColumn => @@ -403,6 +441,49 @@ class RenderTableViewport extends RenderTwoDimensionalViewport { ? _columnMetrics[_lastPinnedColumn]!.trailingOffset : 0.0; + void _debugCheckPinnedExtent() { + assert(() { + if (_pinnedColumnsExtent > viewportDimension.width) { + debugPrint( + 'TableView has pinned columns with a total width of ' + '$_pinnedColumnsExtent, which exceeds the viewport width of ' + '${viewportDimension.width}. This will prevent unpinned columns ' + 'from being visible.', + ); + } else if (_pinnedColumnsExtent == viewportDimension.width) { + final bool hasUnpinnedColumns = + delegate.columnCount == null || + delegate.columnCount! > delegate.pinnedColumnCount; + if (hasUnpinnedColumns) { + debugPrint( + 'TableView has pinned columns that fully consume the viewport width. ' + 'Unpinned columns will not be visible.', + ); + } + } + + if (_pinnedRowsExtent > viewportDimension.height) { + debugPrint( + 'TableView has pinned rows with a total height of ' + '$_pinnedRowsExtent, which exceeds the viewport height of ' + '${viewportDimension.height}. This will prevent unpinned rows ' + 'from being visible.', + ); + } else if (_pinnedRowsExtent == viewportDimension.height) { + final bool hasUnpinnedRows = + delegate.rowCount == null || + delegate.rowCount! > delegate.pinnedRowCount; + if (hasUnpinnedRows) { + debugPrint( + 'TableView has pinned rows that fully consume the viewport height. ' + 'Unpinned rows will not be visible.', + ); + } + } + return true; + }()); + } + @override TableViewParentData parentDataOf(RenderBox child) => super.parentDataOf(child) as TableViewParentData; @@ -847,11 +928,39 @@ class RenderTableViewport extends RenderTwoDimensionalViewport { _updateColumnMetrics(); _updateRowMetrics(); _updateScrollBounds(); + _debugCheckPinnedExtent(); } else { // Updates the visible cells based on cached table metrics. _updateFirstAndLastVisibleCell(); } + final Alignment resolvedAlignment = alignment.resolve(textDirection); + _hAlignmentOffset = 0.0; + if (!_columnsAreInfinite && _columnMetrics.isNotEmpty) { + final double totalWidth = + _pinnedColumnsExtent + + _columnMetrics[delegate.columnCount! - 1]!.trailingOffset; + if (totalWidth < viewportDimension.width) { + _hAlignmentOffset = + (viewportDimension.width - totalWidth) * + (resolvedAlignment.x + 1.0) / + 2.0; + } + } + + _vAlignmentOffset = 0.0; + if (!_rowsAreInfinite && _rowMetrics.isNotEmpty) { + final double totalHeight = + _pinnedRowsExtent + + _rowMetrics[delegate.rowCount! - 1]!.trailingOffset; + if (totalHeight < viewportDimension.height) { + _vAlignmentOffset = + (viewportDimension.height - totalHeight) * + (resolvedAlignment.y + 1.0) / + 2.0; + } + } + if (_firstNonPinnedCell == null && _lastPinnedRow == null && _lastPinnedColumn == null) { @@ -862,19 +971,21 @@ class RenderTableViewport extends RenderTwoDimensionalViewport { final double? offsetIntoColumn = _firstNonPinnedColumn != null ? horizontalOffset.pixels - _columnMetrics[_firstNonPinnedColumn]!.leadingOffset - - _pinnedColumnsExtent + _pinnedColumnsExtent - + _hAlignmentOffset : null; final double? offsetIntoRow = _firstNonPinnedRow != null ? verticalOffset.pixels - _rowMetrics[_firstNonPinnedRow]!.leadingOffset - - _pinnedRowsExtent + _pinnedRowsExtent - + _vAlignmentOffset : null; if (_lastPinnedRow != null && _lastPinnedColumn != null) { // Layout cells that are contained in both pinned rows and columns _layoutCells( start: TableVicinity.zero, end: TableVicinity(column: _lastPinnedColumn!, row: _lastPinnedRow!), - offset: Offset.zero, + offset: Offset(-_hAlignmentOffset, -_vAlignmentOffset), ); } @@ -886,7 +997,7 @@ class RenderTableViewport extends RenderTwoDimensionalViewport { _layoutCells( start: TableVicinity(column: _firstNonPinnedColumn!, row: 0), end: TableVicinity(column: _lastNonPinnedColumn!, row: _lastPinnedRow!), - offset: Offset(offsetIntoColumn!, 0), + offset: Offset(offsetIntoColumn!, -_vAlignmentOffset), ); } if (_lastPinnedColumn != null && _firstNonPinnedRow != null) { @@ -897,7 +1008,7 @@ class RenderTableViewport extends RenderTwoDimensionalViewport { _layoutCells( start: TableVicinity(column: 0, row: _firstNonPinnedRow!), end: TableVicinity(column: _lastPinnedColumn!, row: _lastNonPinnedRow!), - offset: Offset(0, offsetIntoRow!), + offset: Offset(-_hAlignmentOffset, offsetIntoRow!), ); } if (_firstNonPinnedCell != null) { @@ -1176,6 +1287,9 @@ class RenderTableViewport extends RenderTwoDimensionalViewport { // follows row or column major ordering. Here is slightly different // as we break the cells up into 4 main paint passes to clip for overlap. + final bool reversedH = axisDirectionIsReversed(horizontalAxisDirection); + final bool reversedV = axisDirectionIsReversed(verticalAxisDirection); + if (_firstNonPinnedCell != null) { // Paint all visible un-pinned cells assert(_lastNonPinnedCell != null); @@ -1183,12 +1297,10 @@ class RenderTableViewport extends RenderTwoDimensionalViewport { needsCompositing, offset, Rect.fromLTWH( - axisDirectionIsReversed(horizontalAxisDirection) - ? 0.0 - : _pinnedColumnsExtent, - axisDirectionIsReversed(verticalAxisDirection) - ? 0.0 - : _pinnedRowsExtent, + (reversedH ? 0.0 : _pinnedColumnsExtent) + + (reversedH ? -_hAlignmentOffset : _hAlignmentOffset), + (reversedV ? 0.0 : _pinnedRowsExtent) + + (reversedV ? -_vAlignmentOffset : _vAlignmentOffset), viewportDimension.width - _pinnedColumnsExtent, viewportDimension.height - _pinnedRowsExtent, ), @@ -1214,12 +1326,13 @@ class RenderTableViewport extends RenderTwoDimensionalViewport { needsCompositing, offset, Rect.fromLTWH( - axisDirectionIsReversed(horizontalAxisDirection) - ? viewportDimension.width - _pinnedColumnsExtent - : 0.0, - axisDirectionIsReversed(verticalAxisDirection) - ? 0.0 - : _pinnedRowsExtent, + reversedH + ? viewportDimension.width - + _pinnedColumnsExtent - + _hAlignmentOffset + : _hAlignmentOffset, + (reversedV ? 0.0 : _pinnedRowsExtent) + + (reversedV ? -_vAlignmentOffset : _vAlignmentOffset), _pinnedColumnsExtent, viewportDimension.height - _pinnedRowsExtent, ), @@ -1248,12 +1361,11 @@ class RenderTableViewport extends RenderTwoDimensionalViewport { needsCompositing, offset, Rect.fromLTWH( - axisDirectionIsReversed(horizontalAxisDirection) - ? 0.0 - : _pinnedColumnsExtent, - axisDirectionIsReversed(verticalAxisDirection) - ? viewportDimension.height - _pinnedRowsExtent - : 0.0, + (reversedH ? 0.0 : _pinnedColumnsExtent) + + (reversedH ? -_hAlignmentOffset : _hAlignmentOffset), + reversedV + ? viewportDimension.height - _pinnedRowsExtent - _vAlignmentOffset + : _vAlignmentOffset, viewportDimension.width - _pinnedColumnsExtent, _pinnedRowsExtent, ), @@ -1336,7 +1448,6 @@ class RenderTableViewport extends RenderTwoDimensionalViewport { final foregroundColumns = {}; final backgroundColumns = {}; - final TableSpan rowSpan = _rowMetrics[leadingVicinity.row]!.configuration; for ( int column = leadingVicinity.column; column <= trailingVicinity.column; @@ -1415,27 +1526,45 @@ class RenderTableViewport extends RenderTwoDimensionalViewport { required RenderBox trailingCell, required bool consumePadding, }) { - final ({double leading, double trailing}) offsetCorrection = - axisDirectionIsReversed(verticalAxisDirection) - ? ( - leading: leadingCell.size.height, - trailing: trailingCell.size.height, - ) - : (leading: 0.0, trailing: 0.0); - return Rect.fromPoints( - parentDataOf(leadingCell).paintOffset! + - offset - - Offset( - consumePadding ? columnSpan.padding.leading : 0.0, - rowSpan.padding.leading - offsetCorrection.leading, - ), - parentDataOf(trailingCell).paintOffset! + - offset + - Offset(trailingCell.size.width, trailingCell.size.height) + - Offset( - consumePadding ? columnSpan.padding.trailing : 0.0, - rowSpan.padding.trailing - offsetCorrection.trailing, - ), + final bool reversedH = axisDirectionIsReversed( + horizontalAxisDirection, + ); + final bool reversedV = axisDirectionIsReversed(verticalAxisDirection); + final TableSpan leadingRowSpan = + _rowMetrics[parentDataOf(leadingCell).tableVicinity.row]! + .configuration; + final TableSpan trailingRowSpan = + _rowMetrics[parentDataOf(trailingCell).tableVicinity.row]! + .configuration; + + final double leftExpansion = consumePadding + ? (reversedH + ? columnSpan.padding.trailing + : columnSpan.padding.leading) + : 0.0; + final double rightExpansion = consumePadding + ? (reversedH + ? columnSpan.padding.leading + : columnSpan.padding.trailing) + : 0.0; + final double topExpansion = reversedV + ? trailingRowSpan.padding.trailing + : leadingRowSpan.padding.leading; + final double bottomExpansion = reversedV + ? leadingRowSpan.padding.leading + : trailingRowSpan.padding.trailing; + + final Offset p1 = parentDataOf(leadingCell).paintOffset! + offset; + final Offset p2 = + parentDataOf(trailingCell).paintOffset! + + offset + + Offset(trailingCell.size.width, trailingCell.size.height); + + return Rect.fromLTRB( + math.min(p1.dx, p2.dx - trailingCell.size.width) - leftExpansion, + math.min(p1.dy, p2.dy - trailingCell.size.height) - topExpansion, + math.max(p1.dx + leadingCell.size.width, p2.dx) + rightExpansion, + math.max(p1.dy + leadingCell.size.height, p2.dy) + bottomExpansion, ); } @@ -1471,8 +1600,6 @@ class RenderTableViewport extends RenderTwoDimensionalViewport { // Row decorations final foregroundRows = {}; final backgroundRows = {}; - final TableSpan columnSpan = - _columnMetrics[leadingVicinity.column]!.configuration; for (int row = leadingVicinity.row; row <= trailingVicinity.row; row++) { TableSpan rowSpan = _rowMetrics[row]!.configuration; if (rowSpan.backgroundDecoration != null || @@ -1547,27 +1674,41 @@ class RenderTableViewport extends RenderTwoDimensionalViewport { required RenderBox trailingCell, required bool consumePadding, }) { - final ({double leading, double trailing}) offsetCorrection = - axisDirectionIsReversed(horizontalAxisDirection) - ? ( - leading: leadingCell.size.width, - trailing: trailingCell.size.width, - ) - : (leading: 0.0, trailing: 0.0); - return Rect.fromPoints( - parentDataOf(leadingCell).paintOffset! + - offset - - Offset( - columnSpan.padding.leading - offsetCorrection.leading, - consumePadding ? rowSpan.padding.leading : 0.0, - ), - parentDataOf(trailingCell).paintOffset! + - offset + - Offset(trailingCell.size.width, trailingCell.size.height) + - Offset( - columnSpan.padding.leading - offsetCorrection.trailing, - consumePadding ? rowSpan.padding.trailing : 0.0, - ), + final bool reversedH = axisDirectionIsReversed( + horizontalAxisDirection, + ); + final bool reversedV = axisDirectionIsReversed(verticalAxisDirection); + final TableSpan leadingColSpan = + _columnMetrics[parentDataOf(leadingCell).tableVicinity.column]! + .configuration; + final TableSpan trailingColSpan = + _columnMetrics[parentDataOf(trailingCell).tableVicinity.column]! + .configuration; + + final double leftExpansion = reversedH + ? trailingColSpan.padding.trailing + : leadingColSpan.padding.leading; + final double rightExpansion = reversedH + ? leadingColSpan.padding.leading + : trailingColSpan.padding.trailing; + final double topExpansion = consumePadding + ? (reversedV ? rowSpan.padding.trailing : rowSpan.padding.leading) + : 0.0; + final double bottomExpansion = consumePadding + ? (reversedV ? rowSpan.padding.leading : rowSpan.padding.trailing) + : 0.0; + + final Offset p1 = parentDataOf(leadingCell).paintOffset! + offset; + final Offset p2 = + parentDataOf(trailingCell).paintOffset! + + offset + + Offset(trailingCell.size.width, trailingCell.size.height); + + return Rect.fromLTRB( + math.min(p1.dx, p2.dx - trailingCell.size.width) - leftExpansion, + math.min(p1.dy, p2.dy - trailingCell.size.height) - topExpansion, + math.max(p1.dx + leadingCell.size.width, p2.dx) + rightExpansion, + math.max(p1.dy + leadingCell.size.height, p2.dy) + bottomExpansion, ); } @@ -1612,6 +1753,7 @@ class RenderTableViewport extends RenderTwoDimensionalViewport { canvas: context.canvas, rect: rect, axisDirection: horizontalAxisDirection, + crossAxisDirection: verticalAxisDirection, ); decoration.paint(paintingDetails); }); @@ -1620,6 +1762,7 @@ class RenderTableViewport extends RenderTwoDimensionalViewport { canvas: context.canvas, rect: rect, axisDirection: verticalAxisDirection, + crossAxisDirection: horizontalAxisDirection, ); decoration.paint(paintingDetails); }); @@ -1630,6 +1773,7 @@ class RenderTableViewport extends RenderTwoDimensionalViewport { canvas: context.canvas, rect: rect, axisDirection: verticalAxisDirection, + crossAxisDirection: horizontalAxisDirection, ); decoration.paint(paintingDetails); }); @@ -1638,6 +1782,7 @@ class RenderTableViewport extends RenderTwoDimensionalViewport { canvas: context.canvas, rect: rect, axisDirection: horizontalAxisDirection, + crossAxisDirection: verticalAxisDirection, ); decoration.paint(paintingDetails); }); @@ -1682,6 +1827,7 @@ class RenderTableViewport extends RenderTwoDimensionalViewport { canvas: context.canvas, rect: rect, axisDirection: horizontalAxisDirection, + crossAxisDirection: verticalAxisDirection, ); decoration.paint(paintingDetails); }); @@ -1690,6 +1836,7 @@ class RenderTableViewport extends RenderTwoDimensionalViewport { canvas: context.canvas, rect: rect, axisDirection: verticalAxisDirection, + crossAxisDirection: horizontalAxisDirection, ); decoration.paint(paintingDetails); }); @@ -1700,6 +1847,7 @@ class RenderTableViewport extends RenderTwoDimensionalViewport { canvas: context.canvas, rect: rect, axisDirection: verticalAxisDirection, + crossAxisDirection: horizontalAxisDirection, ); decoration.paint(paintingDetails); }); @@ -1708,6 +1856,7 @@ class RenderTableViewport extends RenderTwoDimensionalViewport { canvas: context.canvas, rect: rect, axisDirection: horizontalAxisDirection, + crossAxisDirection: verticalAxisDirection, ); decoration.paint(paintingDetails); }); diff --git a/packages/two_dimensional_scrollables/lib/src/tree_view/render_tree.dart b/packages/two_dimensional_scrollables/lib/src/tree_view/render_tree.dart index 1c077c63f2a3..10eb1ac3646a 100644 --- a/packages/two_dimensional_scrollables/lib/src/tree_view/render_tree.dart +++ b/packages/two_dimensional_scrollables/lib/src/tree_view/render_tree.dart @@ -38,9 +38,13 @@ class RenderTreeViewport extends RenderTwoDimensionalViewport { required super.childManager, super.cacheExtent, super.clipBehavior, + AlignmentGeometry alignment = Alignment.topLeft, + TextDirection? textDirection, }) : _activeAnimations = activeAnimations, _rowDepths = rowDepths, _indentation = indentation, + _alignment = alignment, + _textDirection = textDirection, assert(indentation >= 0), assert( verticalAxisDirection == AxisDirection.down && @@ -56,6 +60,30 @@ class RenderTreeViewport extends RenderTwoDimensionalViewport { super.delegate = value; } + /// The alignment of the tree within the viewport when there is extra space. + AlignmentGeometry get alignment => _alignment; + AlignmentGeometry _alignment; + set alignment(AlignmentGeometry value) { + if (_alignment == value) { + return; + } + _alignment = value; + markNeedsLayout(); + } + + /// The text direction with which to resolve [alignment]. + TextDirection? get textDirection => _textDirection; + TextDirection? _textDirection; + set textDirection(TextDirection? value) { + if (_textDirection == value) { + return; + } + _textDirection = value; + markNeedsLayout(); + } + + double _vAlignmentOffset = 0.0; + /// The currently active [TreeViewNode] animations. /// /// Since the index of animating nodes can change at any time, the unique key @@ -348,6 +376,19 @@ class RenderTreeViewport extends RenderTwoDimensionalViewport { _updateFirstAndLastVisibleRow(); } + final Alignment resolvedAlignment = alignment.resolve(textDirection); + _vAlignmentOffset = 0.0; + if (_rowMetrics.isNotEmpty) { + final double totalHeight = + _rowMetrics[_rowMetrics.length - 1]!.trailingOffset; + if (totalHeight < viewportDimension.height) { + _vAlignmentOffset = + (viewportDimension.height - totalHeight) * + (resolvedAlignment.y + 1.0) / + 2.0; + } + } + if (_firstRow == null) { assert(_lastRow == null); return; @@ -356,7 +397,9 @@ class RenderTreeViewport extends RenderTwoDimensionalViewport { _Span rowSpan; double rowOffset = - -verticalOffset.pixels + _rowMetrics[_firstRow!]!.leadingOffset; + -verticalOffset.pixels + + _rowMetrics[_firstRow!]!.leadingOffset + + _vAlignmentOffset; for (int row = _firstRow!; row <= _lastRow!; row++) { rowSpan = _rowMetrics[row]!; final double rowHeight = rowSpan.extent; @@ -489,11 +532,11 @@ class RenderTreeViewport extends RenderTwoDimensionalViewport { final double trailingOffset = _rowMetrics[segment.trailingIndex]!.trailingOffset; final rect = Rect.fromPoints( - Offset(0.0, leadingOffset - verticalOffset.pixels), + Offset(0.0, leadingOffset - verticalOffset.pixels + _vAlignmentOffset), Offset( viewportDimension.width, math.min( - trailingOffset - verticalOffset.pixels, + trailingOffset - verticalOffset.pixels + _vAlignmentOffset, viewportDimension.height, ), ), @@ -545,12 +588,14 @@ class RenderTreeViewport extends RenderTwoDimensionalViewport { ); // Decoration rects cover the whole row from the left and right // edge of the viewport. - return Rect.fromPoints( - Offset(0.0, parentData.layoutOffset!.dy), - Offset( - viewportDimension.width, - rowSpan.trailingOffset - verticalOffset.pixels, - ), + return Rect.fromLTRB( + 0.0, + parentData.paintOffset!.dy - + (consumePadding ? rowSpan.configuration.padding.leading : 0.0), + viewportDimension.width, + parentData.paintOffset!.dy + + child.size.height + + (consumePadding ? rowSpan.configuration.padding.trailing : 0.0), ); } @@ -577,6 +622,7 @@ class RenderTreeViewport extends RenderTwoDimensionalViewport { canvas: context.canvas, rect: rect, axisDirection: horizontalAxisDirection, + crossAxisDirection: verticalAxisDirection, ); decoration.paint(paintingDetails); }); @@ -598,6 +644,7 @@ class RenderTreeViewport extends RenderTwoDimensionalViewport { canvas: context.canvas, rect: rect, axisDirection: horizontalAxisDirection, + crossAxisDirection: verticalAxisDirection, ); decoration.paint(paintingDetails); }); diff --git a/packages/two_dimensional_scrollables/lib/src/tree_view/tree.dart b/packages/two_dimensional_scrollables/lib/src/tree_view/tree.dart index 3c5fa67bf134..6819c9424018 100644 --- a/packages/two_dimensional_scrollables/lib/src/tree_view/tree.dart +++ b/packages/two_dimensional_scrollables/lib/src/tree_view/tree.dart @@ -322,6 +322,7 @@ class TreeView extends StatefulWidget { this.clipBehavior = Clip.hardEdge, this.addAutomaticKeepAlives = true, this.addRepaintBoundaries = true, + this.alignment = Alignment.topLeft, }) : assert( verticalDetails.direction == AxisDirection.down && horizontalDetails.direction == AxisDirection.right, @@ -496,6 +497,14 @@ class TreeView extends StatefulWidget { /// Defaults to true. final bool addRepaintBoundaries; + /// The alignment of the tree within the viewport when there is extra space. + /// + /// Currently, [TreeView] only supports the vertical component of [alignment] + /// for aligning the tree within the viewport. + /// + /// Defaults to [Alignment.topLeft]. + final AlignmentGeometry alignment; + /// The default [AnimationStyle] used for node expand and collapse animations, /// when one has not been provided in [toggleAnimationStyle]. // ignore: prefer_const_constructors @@ -758,6 +767,7 @@ class _TreeViewState extends State> }, addAutomaticKeepAlives: widget.addAutomaticKeepAlives, indentation: widget.indentation.value, + alignment: widget.alignment, ); } @@ -984,6 +994,7 @@ class _TreeView extends TwoDimensionalScrollView { required this.activeAnimations, required this.rowDepths, required this.indentation, + required this.alignment, required int rowCount, bool addAutomaticKeepAlives = true, }) : assert(verticalDetails.direction == AxisDirection.down), @@ -1000,6 +1011,7 @@ class _TreeView extends TwoDimensionalScrollView { final Map activeAnimations; final Map rowDepths; final double indentation; + final AlignmentGeometry alignment; @override TreeViewport buildViewport( @@ -1018,6 +1030,7 @@ class _TreeView extends TwoDimensionalScrollView { activeAnimations: activeAnimations, rowDepths: rowDepths, indentation: indentation, + alignment: alignment, ); } } @@ -1039,6 +1052,7 @@ class TreeViewport extends TwoDimensionalViewport { required this.activeAnimations, required this.rowDepths, required this.indentation, + this.alignment = Alignment.topLeft, }) : assert( verticalAxisDirection == AxisDirection.down && horizontalAxisDirection == AxisDirection.right, @@ -1063,6 +1077,9 @@ class TreeViewport extends TwoDimensionalViewport { /// for more options to customize the indented space. final double indentation; + /// The alignment of the tree within the viewport when there is extra space. + final AlignmentGeometry alignment; + @override RenderTreeViewport createRenderObject(BuildContext context) { return RenderTreeViewport( @@ -1077,6 +1094,8 @@ class TreeViewport extends TwoDimensionalViewport { clipBehavior: clipBehavior, delegate: delegate as TreeRowDelegateMixin, childManager: context as TwoDimensionalChildManager, + alignment: alignment, + textDirection: Directionality.maybeOf(context), ); } @@ -1095,6 +1114,8 @@ class TreeViewport extends TwoDimensionalViewport { ..verticalAxisDirection = verticalAxisDirection ..cacheExtent = cacheExtent ..clipBehavior = clipBehavior - ..delegate = delegate as TreeRowDelegateMixin; + ..delegate = delegate as TreeRowDelegateMixin + ..alignment = alignment + ..textDirection = Directionality.maybeOf(context); } } diff --git a/packages/two_dimensional_scrollables/lib/src/tree_view/tree_span.dart b/packages/two_dimensional_scrollables/lib/src/tree_view/tree_span.dart index 3c6f8dd65fec..d64f989f07fc 100644 --- a/packages/two_dimensional_scrollables/lib/src/tree_view/tree_span.dart +++ b/packages/two_dimensional_scrollables/lib/src/tree_view/tree_span.dart @@ -103,7 +103,15 @@ class TreeRowBorder extends SpanBorder { @override void paint(SpanDecorationPaintDetails details, BorderRadius? borderRadius) { - final border = Border(top: top, bottom: bottom, left: left, right: right); + final AxisDirection? crossAxisDirection = details.crossAxisDirection; + final bool isLeadingTop = + crossAxisDirection == null || crossAxisDirection == AxisDirection.down; + final border = Border( + top: isLeadingTop ? top : bottom, + bottom: isLeadingTop ? bottom : top, + left: left, + right: right, + ); border.paint(details.canvas, details.rect, borderRadius: borderRadius); } } diff --git a/packages/two_dimensional_scrollables/pubspec.yaml b/packages/two_dimensional_scrollables/pubspec.yaml index c17706a2af68..8e6d131bc8e0 100644 --- a/packages/two_dimensional_scrollables/pubspec.yaml +++ b/packages/two_dimensional_scrollables/pubspec.yaml @@ -1,6 +1,6 @@ name: two_dimensional_scrollables description: Widgets that scroll using the two dimensional scrolling foundation. -version: 0.3.8 +version: 0.4.1 repository: https://github.com/flutter/packages/tree/main/packages/two_dimensional_scrollables issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+two_dimensional_scrollables%22+ diff --git a/packages/two_dimensional_scrollables/test/table_view/alignment_test.dart b/packages/two_dimensional_scrollables/test/table_view/alignment_test.dart new file mode 100644 index 000000000000..cba1e1fbc872 --- /dev/null +++ b/packages/two_dimensional_scrollables/test/table_view/alignment_test.dart @@ -0,0 +1,608 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter/widgets.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:two_dimensional_scrollables/two_dimensional_scrollables.dart'; + +void main() { + group('TableView alignment', () { + testWidgets('Default alignment - topLeft', (WidgetTester tester) async { + await tester.pumpWidget( + WidgetsApp( + color: const Color(0xFFFFFFFF), + debugShowCheckedModeBanner: false, + builder: (context, child) => Directionality( + textDirection: TextDirection.ltr, + child: Align( + alignment: Alignment.topLeft, + child: SizedBox( + width: 600, + height: 600, + child: TableView.builder( + columnCount: 1, + rowCount: 1, + columnBuilder: (index) => + const TableSpan(extent: FixedTableSpanExtent(100)), + rowBuilder: (index) => + const TableSpan(extent: FixedTableSpanExtent(100)), + cellBuilder: (context, vicinity) { + return TableViewCell( + child: SizedBox( + key: ValueKey( + 'cell ${vicinity.column}:${vicinity.row}', + ), + ), + ); + }, + ), + ), + ), + ), + ), + ); + + final Offset tableTopLeft = tester.getTopLeft(find.byType(TableView)); + // Default is Alignment.topLeft (0, 0) + final Finder cell00 = find.byKey(const ValueKey('cell 0:0')); + expect(tester.getTopLeft(cell00) - tableTopLeft, Offset.zero); + }); + + testWidgets('Horizontal alignment - center', (WidgetTester tester) async { + const viewportWidth = 600.0; + + await tester.pumpWidget( + WidgetsApp( + color: const Color(0xFFFFFFFF), + debugShowCheckedModeBanner: false, + builder: (context, child) => Directionality( + textDirection: TextDirection.ltr, + child: Align( + alignment: Alignment.topLeft, + child: SizedBox( + width: viewportWidth, + height: 400, + child: TableView.builder( + columnCount: 3, + rowCount: 1, + alignment: Alignment.topCenter, + columnBuilder: (index) => + const TableSpan(extent: FixedTableSpanExtent(100)), + rowBuilder: (index) => + const TableSpan(extent: FixedTableSpanExtent(100)), + cellBuilder: (context, vicinity) { + return TableViewCell( + child: SizedBox( + key: ValueKey( + 'cell ${vicinity.column}:${vicinity.row}', + ), + ), + ); + }, + ), + ), + ), + ), + ), + ); + + final Offset tableTopLeft = tester.getTopLeft(find.byType(TableView)); + // Table is 300 wide, viewport is 600 wide. Centered means 150 offset. + final Finder cell00 = find.byKey(const ValueKey('cell 0:0')); + expect( + tester.getTopLeft(cell00) - tableTopLeft, + const Offset(150.0, 0.0), + ); + + final Finder cell20 = find.byKey(const ValueKey('cell 2:0')); + expect( + tester.getTopLeft(cell20) - tableTopLeft, + const Offset(350.0, 0.0), + ); + }); + + testWidgets('Horizontal alignment - end', (WidgetTester tester) async { + const viewportWidth = 600.0; + + await tester.pumpWidget( + WidgetsApp( + color: const Color(0xFFFFFFFF), + debugShowCheckedModeBanner: false, + builder: (context, child) => Directionality( + textDirection: TextDirection.ltr, + child: Align( + alignment: Alignment.topLeft, + child: SizedBox( + width: viewportWidth, + height: 400, + child: TableView.builder( + columnCount: 3, + rowCount: 1, + alignment: Alignment.topRight, + columnBuilder: (index) => + const TableSpan(extent: FixedTableSpanExtent(100)), + rowBuilder: (index) => + const TableSpan(extent: FixedTableSpanExtent(100)), + cellBuilder: (context, vicinity) { + return TableViewCell( + child: SizedBox( + key: ValueKey( + 'cell ${vicinity.column}:${vicinity.row}', + ), + ), + ); + }, + ), + ), + ), + ), + ), + ); + + final Offset tableTopLeft = tester.getTopLeft(find.byType(TableView)); + // Table is 300 wide, viewport is 600 wide. End means 300 offset. + final Finder cell00 = find.byKey(const ValueKey('cell 0:0')); + expect( + tester.getTopLeft(cell00) - tableTopLeft, + const Offset(300.0, 0.0), + ); + }); + + testWidgets('Vertical alignment - center', (WidgetTester tester) async { + const viewportHeight = 600.0; + + await tester.pumpWidget( + WidgetsApp( + color: const Color(0xFFFFFFFF), + debugShowCheckedModeBanner: false, + builder: (context, child) => Directionality( + textDirection: TextDirection.ltr, + child: Align( + alignment: Alignment.topLeft, + child: SizedBox( + width: 400, + height: viewportHeight, + child: TableView.builder( + columnCount: 1, + rowCount: 2, + alignment: Alignment.centerLeft, + columnBuilder: (index) => + const TableSpan(extent: FixedTableSpanExtent(100)), + rowBuilder: (index) => + const TableSpan(extent: FixedTableSpanExtent(100)), + cellBuilder: (context, vicinity) { + return TableViewCell( + child: SizedBox( + key: ValueKey( + 'cell ${vicinity.column}:${vicinity.row}', + ), + ), + ); + }, + ), + ), + ), + ), + ), + ); + + final Offset tableTopLeft = tester.getTopLeft(find.byType(TableView)); + // Table is 200 high, viewport is 600 high. Centered means 200 offset. + final Finder cell00 = find.byKey(const ValueKey('cell 0:0')); + expect( + tester.getTopLeft(cell00) - tableTopLeft, + const Offset(0.0, 200.0), + ); + + final Finder cell01 = find.byKey(const ValueKey('cell 0:1')); + expect( + tester.getTopLeft(cell01) - tableTopLeft, + const Offset(0.0, 300.0), + ); + }); + + testWidgets('Combined alignment', (WidgetTester tester) async { + await tester.pumpWidget( + WidgetsApp( + color: const Color(0xFFFFFFFF), + debugShowCheckedModeBanner: false, + builder: (context, child) => Directionality( + textDirection: TextDirection.ltr, + child: Align( + alignment: Alignment.topLeft, + child: SizedBox( + width: 600, + height: 600, + child: TableView.builder( + columnCount: 1, + rowCount: 1, + alignment: Alignment.center, + columnBuilder: (index) => + const TableSpan(extent: FixedTableSpanExtent(100)), + rowBuilder: (index) => + const TableSpan(extent: FixedTableSpanExtent(100)), + cellBuilder: (context, vicinity) { + return TableViewCell( + child: SizedBox( + key: ValueKey( + 'cell ${vicinity.column}:${vicinity.row}', + ), + ), + ); + }, + ), + ), + ), + ), + ), + ); + + final Offset tableTopLeft = tester.getTopLeft(find.byType(TableView)); + // Table is 100x100, viewport is 600x600. Centered means 250, 250 offset. + final Finder cell00 = find.byKey(const ValueKey('cell 0:0')); + expect( + tester.getTopLeft(cell00) - tableTopLeft, + const Offset(250.0, 250.0), + ); + }); + + testWidgets('Alignment with pinned columns', (WidgetTester tester) async { + await tester.pumpWidget( + WidgetsApp( + color: const Color(0xFFFFFFFF), + debugShowCheckedModeBanner: false, + builder: (context, child) => Directionality( + textDirection: TextDirection.ltr, + child: Align( + alignment: Alignment.topLeft, + child: SizedBox( + width: 600, + height: 400, + child: TableView.builder( + columnCount: 3, + rowCount: 1, + pinnedColumnCount: 1, + alignment: Alignment.topCenter, + columnBuilder: (index) => + const TableSpan(extent: FixedTableSpanExtent(100)), + rowBuilder: (index) => + const TableSpan(extent: FixedTableSpanExtent(100)), + cellBuilder: (context, vicinity) { + return TableViewCell( + child: SizedBox( + key: ValueKey( + 'cell ${vicinity.column}:${vicinity.row}', + ), + ), + ); + }, + ), + ), + ), + ), + ), + ); + + final Offset tableTopLeft = tester.getTopLeft(find.byType(TableView)); + // Total width 300 (1 pinned, 2 unpinned). Viewport 600. Offset 150. + // Pinned column 0 should be at 150. + final Finder cell00 = find.byKey(const ValueKey('cell 0:0')); + expect( + tester.getTopLeft(cell00) - tableTopLeft, + const Offset(150.0, 0.0), + ); + + // Unpinned column 1 should be at 250. + final Finder cell10 = find.byKey(const ValueKey('cell 1:0')); + expect( + tester.getTopLeft(cell10) - tableTopLeft, + const Offset(250.0, 0.0), + ); + }); + + testWidgets('Alignment with pinned rows', (WidgetTester tester) async { + await tester.pumpWidget( + WidgetsApp( + color: const Color(0xFFFFFFFF), + debugShowCheckedModeBanner: false, + builder: (context, child) => Directionality( + textDirection: TextDirection.ltr, + child: Align( + alignment: Alignment.topLeft, + child: SizedBox( + width: 400, + height: 600, + child: TableView.builder( + columnCount: 1, + rowCount: 3, + pinnedRowCount: 1, + alignment: Alignment.centerLeft, + columnBuilder: (index) => + const TableSpan(extent: FixedTableSpanExtent(100)), + rowBuilder: (index) => + const TableSpan(extent: FixedTableSpanExtent(100)), + cellBuilder: (context, vicinity) { + return TableViewCell( + child: SizedBox( + key: ValueKey( + 'cell ${vicinity.column}:${vicinity.row}', + ), + ), + ); + }, + ), + ), + ), + ), + ), + ); + + final Offset tableTopLeft = tester.getTopLeft(find.byType(TableView)); + // Total height 300 (1 pinned, 2 unpinned). Viewport 600. Offset 150. + // Pinned row 0 should be at 150. + final Finder cell00 = find.byKey(const ValueKey('cell 0:0')); + expect( + tester.getTopLeft(cell00) - tableTopLeft, + const Offset(0.0, 150.0), + ); + + // Unpinned row 1 should be at 250. + final Finder cell01 = find.byKey(const ValueKey('cell 0:1')); + expect( + tester.getTopLeft(cell01) - tableTopLeft, + const Offset(0.0, 250.0), + ); + }); + + testWidgets('Alignment with reversed horizontal axis', ( + WidgetTester tester, + ) async { + await tester.pumpWidget( + WidgetsApp( + color: const Color(0xFFFFFFFF), + debugShowCheckedModeBanner: false, + builder: (context, child) => Directionality( + textDirection: TextDirection.ltr, + child: Align( + alignment: Alignment.topLeft, + child: SizedBox( + width: 600, + height: 400, + child: TableView.builder( + columnCount: 1, + rowCount: 1, + alignment: Alignment.topCenter, + horizontalDetails: const ScrollableDetails.horizontal( + reverse: true, + ), + columnBuilder: (index) => + const TableSpan(extent: FixedTableSpanExtent(100)), + rowBuilder: (index) => + const TableSpan(extent: FixedTableSpanExtent(100)), + cellBuilder: (context, vicinity) { + return TableViewCell( + child: SizedBox( + key: ValueKey( + 'cell ${vicinity.column}:${vicinity.row}', + ), + ), + ); + }, + ), + ), + ), + ), + ), + ); + + final Offset tableTopLeft = tester.getTopLeft(find.byType(TableView)); + // Reversed horizontal. Start is on the right (600). + // Center should still be at 250. + final Finder cell00 = find.byKey(const ValueKey('cell 0:0')); + expect( + tester.getTopLeft(cell00) - tableTopLeft, + const Offset(250.0, 0.0), + ); + }); + + testWidgets('Alignment with reversed vertical axis', ( + WidgetTester tester, + ) async { + await tester.pumpWidget( + WidgetsApp( + color: const Color(0xFFFFFFFF), + debugShowCheckedModeBanner: false, + builder: (context, child) => Directionality( + textDirection: TextDirection.ltr, + child: Align( + alignment: Alignment.topLeft, + child: SizedBox( + width: 400, + height: 600, + child: TableView.builder( + columnCount: 1, + rowCount: 1, + alignment: Alignment.centerLeft, + verticalDetails: const ScrollableDetails.vertical( + reverse: true, + ), + columnBuilder: (index) => + const TableSpan(extent: FixedTableSpanExtent(100)), + rowBuilder: (index) => + const TableSpan(extent: FixedTableSpanExtent(100)), + cellBuilder: (context, vicinity) { + return TableViewCell( + child: SizedBox( + key: ValueKey( + 'cell ${vicinity.column}:${vicinity.row}', + ), + ), + ); + }, + ), + ), + ), + ), + ), + ); + + final Offset tableTopLeft = tester.getTopLeft(find.byType(TableView)); + // Reversed vertical. Center should still be at 250. + final Finder cell00 = find.byKey(const ValueKey('cell 0:0')); + expect( + tester.getTopLeft(cell00) - tableTopLeft, + const Offset(0.0, 250.0), + ); + }); + + testWidgets('Alignment with both axes reversed', ( + WidgetTester tester, + ) async { + await tester.pumpWidget( + WidgetsApp( + color: const Color(0xFFFFFFFF), + debugShowCheckedModeBanner: false, + builder: (context, child) => Directionality( + textDirection: TextDirection.ltr, + child: Align( + alignment: Alignment.topLeft, + child: SizedBox( + width: 600, + height: 600, + child: TableView.builder( + columnCount: 1, + rowCount: 1, + alignment: Alignment.center, + horizontalDetails: const ScrollableDetails.horizontal( + reverse: true, + ), + verticalDetails: const ScrollableDetails.vertical( + reverse: true, + ), + columnBuilder: (index) => + const TableSpan(extent: FixedTableSpanExtent(100)), + rowBuilder: (index) => + const TableSpan(extent: FixedTableSpanExtent(100)), + cellBuilder: (context, vicinity) { + return TableViewCell( + child: SizedBox( + key: ValueKey( + 'cell ${vicinity.column}:${vicinity.row}', + ), + ), + ); + }, + ), + ), + ), + ), + ), + ); + + final Offset tableTopLeft = tester.getTopLeft(find.byType(TableView)); + // Both reversed. Center should still be at (250, 250). + final Finder cell00 = find.byKey(const ValueKey('cell 0:0')); + expect( + tester.getTopLeft(cell00) - tableTopLeft, + const Offset(250.0, 250.0), + ); + }); + + testWidgets('AlignmentDirectional with RTL', (WidgetTester tester) async { + await tester.pumpWidget( + WidgetsApp( + color: const Color(0xFFFFFFFF), + debugShowCheckedModeBanner: false, + builder: (context, child) => Directionality( + textDirection: TextDirection.rtl, + child: Align( + alignment: Alignment.topLeft, + child: SizedBox( + width: 600, + height: 400, + child: TableView.builder( + columnCount: 1, + rowCount: 1, + alignment: AlignmentDirectional.centerEnd, + columnBuilder: (index) => + const TableSpan(extent: FixedTableSpanExtent(100)), + rowBuilder: (index) => + const TableSpan(extent: FixedTableSpanExtent(100)), + cellBuilder: (context, vicinity) { + return TableViewCell( + child: SizedBox( + key: ValueKey( + 'cell ${vicinity.column}:${vicinity.row}', + ), + ), + ); + }, + ), + ), + ), + ), + ), + ); + + final Offset tableTopLeft = tester.getTopLeft(find.byType(TableView)); + // RTL + centerEnd means alignment to the left. + // Table is 100 wide, viewport 600. centerEnd in RTL resolved to left (x = -1). + // Wait, centerEnd in RTL is actually Alignment(-1.0, 0.0) which is left. + // centerEnd in LTR is Alignment(1.0, 0.0) which is right. + final Finder cell00 = find.byKey(const ValueKey('cell 0:0')); + expect( + tester.getTopLeft(cell00) - tableTopLeft, + const Offset(0.0, 150.0), // Center Y is 150 (400-100)/2 + ); + }); + + testWidgets('Overflow alignment behaves like start in overflow axis', ( + WidgetTester tester, + ) async { + await tester.pumpWidget( + WidgetsApp( + color: const Color(0xFFFFFFFF), + debugShowCheckedModeBanner: false, + builder: (context, child) => Directionality( + textDirection: TextDirection.ltr, + child: Align( + alignment: Alignment.topLeft, + child: SizedBox( + width: 200, + height: 400, + child: TableView.builder( + columnCount: 3, // 300 wide + rowCount: 1, + alignment: Alignment.center, + columnBuilder: (index) => + const TableSpan(extent: FixedTableSpanExtent(100)), + rowBuilder: (index) => + const TableSpan(extent: FixedTableSpanExtent(100)), + cellBuilder: (context, vicinity) { + return TableViewCell( + child: SizedBox( + key: ValueKey( + 'cell ${vicinity.column}:${vicinity.row}', + ), + ), + ); + }, + ), + ), + ), + ), + ), + ); + + final Offset tableTopLeft = tester.getTopLeft(find.byType(TableView)); + // Table (300) > Viewport (200). Horizontal alignment should be ignored (start). + // Viewport (400) > Table (100) Row. Vertical alignment should be center (150). + final Finder cell00 = find.byKey(const ValueKey('cell 0:0')); + expect( + tester.getTopLeft(cell00) - tableTopLeft, + const Offset(0.0, 150.0), + ); + }); + }); +} diff --git a/packages/two_dimensional_scrollables/test/table_view/pinned_extent_warning_test.dart b/packages/two_dimensional_scrollables/test/table_view/pinned_extent_warning_test.dart new file mode 100644 index 000000000000..af0d6625b6e8 --- /dev/null +++ b/packages/two_dimensional_scrollables/test/table_view/pinned_extent_warning_test.dart @@ -0,0 +1,241 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:two_dimensional_scrollables/two_dimensional_scrollables.dart'; + +void main() { + group('TableView pinned extent warnings', () { + testWidgets('Warns when pinned columns exceed viewport width', ( + WidgetTester tester, + ) async { + // Regression test for https://github.com/flutter/flutter/issues/136833 + final log = []; + final DebugPrintCallback oldDebugPrint = debugPrint; + debugPrint = (String? message, {int? wrapWidth}) { + log.add(message!); + }; + + await tester.pumpWidget( + MaterialApp( + home: Scaffold( + body: SizedBox( + width: 200, + height: 400, + child: TableView.builder( + columnCount: 5, + rowCount: 5, + pinnedColumnCount: 3, + columnBuilder: (int index) => + const TableSpan(extent: FixedTableSpanExtent(100)), + rowBuilder: (int index) => + const TableSpan(extent: FixedTableSpanExtent(100)), + cellBuilder: (BuildContext context, TableVicinity vicinity) => + const TableViewCell(child: SizedBox.shrink()), + ), + ), + ), + ), + ); + + // Pinned columns extent = 300 (3 * 100), viewport width = 200. + // A warning is expected because the pinned columns are wider than the + // viewport, meaning even the pinned content cannot be fully displayed. + expect( + log, + contains( + matches( + r'TableView has pinned columns with a total width of 300(\.0)?, which exceeds the viewport width of 200(\.0)?', + ), + ), + ); + debugPrint = oldDebugPrint; + }); + + testWidgets('Warns when pinned rows exceed viewport height', ( + WidgetTester tester, + ) async { + // Regression test for https://github.com/flutter/flutter/issues/136833 + final log = []; + final DebugPrintCallback oldDebugPrint = debugPrint; + debugPrint = (String? message, {int? wrapWidth}) { + log.add(message!); + }; + + await tester.pumpWidget( + MaterialApp( + home: Scaffold( + body: SizedBox( + width: 400, + height: 200, + child: TableView.builder( + columnCount: 5, + rowCount: 5, + pinnedRowCount: 3, + columnBuilder: (int index) => + const TableSpan(extent: FixedTableSpanExtent(100)), + rowBuilder: (int index) => + const TableSpan(extent: FixedTableSpanExtent(100)), + cellBuilder: (BuildContext context, TableVicinity vicinity) => + const TableViewCell(child: SizedBox.shrink()), + ), + ), + ), + ), + ); + + // Pinned rows extent = 300 (3 * 100), viewport height = 200. + // A warning is expected because the pinned rows are taller than the + // viewport, meaning even the pinned content cannot be fully displayed. + expect( + log, + contains( + matches( + r'TableView has pinned rows with a total height of 300(\.0)?, which exceeds the viewport height of 200(\.0)?', + ), + ), + ); + debugPrint = oldDebugPrint; + }); + + testWidgets( + 'Warns when pinned columns fully consume viewport width and there are unpinned columns', + (WidgetTester tester) async { + // Regression test for https://github.com/flutter/flutter/issues/136833 + final log = []; + final DebugPrintCallback oldDebugPrint = debugPrint; + debugPrint = (String? message, {int? wrapWidth}) { + log.add(message!); + }; + + await tester.pumpWidget( + MaterialApp( + home: Scaffold( + body: SizedBox( + width: 200, + height: 400, + child: TableView.builder( + columnCount: 3, + rowCount: 5, + pinnedColumnCount: 2, + columnBuilder: (int index) => + const TableSpan(extent: FixedTableSpanExtent(100)), + rowBuilder: (int index) => + const TableSpan(extent: FixedTableSpanExtent(100)), + cellBuilder: (BuildContext context, TableVicinity vicinity) => + const TableViewCell(child: SizedBox.shrink()), + ), + ), + ), + ), + ); + + // Pinned columns extent = 200 (2 * 100), viewport width = 200. + // There is 1 unpinned column (columnCount: 3, pinnedColumnCount: 2). + // Since the pinned columns take up the entire viewport width, the + // unpinned column will never be visible during scrolling. + expect( + log, + contains( + 'TableView has pinned columns that fully consume the viewport width. Unpinned columns will not be visible.', + ), + ); + debugPrint = oldDebugPrint; + }, + ); + + testWidgets( + 'Warns when pinned rows fully consume viewport height and there are unpinned rows', + (WidgetTester tester) async { + // Regression test for https://github.com/flutter/flutter/issues/136833 + final log = []; + final DebugPrintCallback oldDebugPrint = debugPrint; + debugPrint = (String? message, {int? wrapWidth}) { + log.add(message!); + }; + + await tester.pumpWidget( + MaterialApp( + home: Scaffold( + body: SizedBox( + width: 400, + height: 200, + child: TableView.builder( + columnCount: 5, + rowCount: 3, + pinnedRowCount: 2, + columnBuilder: (int index) => + const TableSpan(extent: FixedTableSpanExtent(100)), + rowBuilder: (int index) => + const TableSpan(extent: FixedTableSpanExtent(100)), + cellBuilder: (BuildContext context, TableVicinity vicinity) => + const TableViewCell(child: SizedBox.shrink()), + ), + ), + ), + ), + ); + + // Pinned rows extent = 200 (2 * 100), viewport height = 200. + // There is 1 unpinned row (rowCount: 3, pinnedRowCount: 2). + // Since the pinned rows take up the entire viewport height, the + // unpinned row will never be visible during scrolling. + expect( + log, + contains( + 'TableView has pinned rows that fully consume the viewport height. Unpinned rows will not be visible.', + ), + ); + debugPrint = oldDebugPrint; + }, + ); + + testWidgets( + 'Does not warn when all columns are pinned even if they consume viewport', + (WidgetTester tester) async { + // Regression test for https://github.com/flutter/flutter/issues/136833 + final log = []; + final DebugPrintCallback oldDebugPrint = debugPrint; + debugPrint = (String? message, {int? wrapWidth}) { + log.add(message!); + }; + + await tester.pumpWidget( + MaterialApp( + home: Scaffold( + body: SizedBox( + width: 200, + height: 400, + child: TableView.builder( + columnCount: 2, + rowCount: 5, + pinnedColumnCount: 2, + columnBuilder: (int index) => + const TableSpan(extent: FixedTableSpanExtent(100)), + rowBuilder: (int index) => + const TableSpan(extent: FixedTableSpanExtent(100)), + cellBuilder: (BuildContext context, TableVicinity vicinity) => + const TableViewCell(child: SizedBox.shrink()), + ), + ), + ), + ), + ); + + // Pinned columns extent = 200 (2 * 100), viewport width = 200. + // Although the pinned columns fully consume the viewport width, + // ALL columns are pinned (columnCount: 2, pinnedColumnCount: 2). + // Since there are no unpinned columns, no warning is issued about + // unpinned columns being hidden. + expect( + log, + isNot(contains(contains('Unpinned columns will not be visible'))), + ); + debugPrint = oldDebugPrint; + }, + ); + }); +} diff --git a/packages/two_dimensional_scrollables/test/table_view/table_span_test.dart b/packages/two_dimensional_scrollables/test/table_view/table_span_test.dart index 4e546e8a9957..ad3a9b8dca44 100644 --- a/packages/two_dimensional_scrollables/test/table_view/table_span_test.dart +++ b/packages/two_dimensional_scrollables/test/table_view/table_span_test.dart @@ -3,7 +3,6 @@ // found in the LICENSE file. import 'package:flutter/material.dart'; -import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:two_dimensional_scrollables/two_dimensional_scrollables.dart'; @@ -850,6 +849,156 @@ void main() { ), ); }); + + testWidgets( + 'paints borders correctly when cross axis is reversed (TableView)', + (WidgetTester tester) async { + // Regression test for https://github.com/flutter/flutter/issues/177117 + final tableView = TableView.builder( + horizontalDetails: const ScrollableDetails.horizontal(reverse: true), + rowCount: 1, + columnCount: 1, + columnBuilder: (int index) => const TableSpan( + extent: FixedTableSpanExtent(200.0), + foregroundDecoration: TableSpanDecoration( + border: TableSpanBorder( + leading: BorderSide(color: Colors.orange, width: 3), + ), + ), + ), + rowBuilder: (int index) => + const TableSpan(extent: FixedTableSpanExtent(200.0)), + cellBuilder: (_, TableVicinity vicinity) { + return TableViewCell( + child: Container( + height: 200, + width: 200, + color: Colors.grey.withValues(alpha: 0.5), + ), + ); + }, + ); + + tester.view.physicalSize = const Size(400, 400); + tester.view.devicePixelRatio = 1.0; + addTearDown(() { + tester.view.resetPhysicalSize(); + tester.view.resetDevicePixelRatio(); + }); + + await tester.pumpWidget(MaterialApp(home: Scaffold(body: tableView))); + await tester.pumpAndSettle(); + + expect( + find.byType(TableViewport), + paints..path( + includes: [ + const Offset(400.0, 0.0), + const Offset(400.0, 200.0), + ], + color: const Color(0xffff9800), + ), + ); + }, + ); + + testWidgets( + 'paints borders correctly when vertical scrolling is reversed (TableView)', + (WidgetTester tester) async { + // Regression test for https://github.com/flutter/flutter/issues/177117 + final tableView = TableView.builder( + verticalDetails: const ScrollableDetails.vertical(reverse: true), + rowCount: 1, + columnCount: 1, + columnBuilder: (int index) => + const TableSpan(extent: FixedTableSpanExtent(200.0)), + rowBuilder: (int index) => const TableSpan( + extent: FixedTableSpanExtent(200.0), + foregroundDecoration: TableSpanDecoration( + border: TableSpanBorder( + leading: BorderSide(color: Colors.orange, width: 3), + ), + ), + ), + cellBuilder: (_, TableVicinity vicinity) { + return TableViewCell( + child: Container( + height: 200, + width: 200, + color: Colors.grey.withValues(alpha: 0.5), + ), + ); + }, + ); + + tester.view.physicalSize = const Size(400, 400); + tester.view.devicePixelRatio = 1.0; + addTearDown(() { + tester.view.resetPhysicalSize(); + tester.view.resetDevicePixelRatio(); + }); + + await tester.pumpWidget(MaterialApp(home: Scaffold(body: tableView))); + await tester.pumpAndSettle(); + + expect( + find.byType(TableViewport), + paints..path( + includes: [ + const Offset(0.0, 400.0), + const Offset(200.0, 400.0), + ], + color: const Color(0xffff9800), + ), + ); + }, + ); + + testWidgets( + 'TableView row decoration rect is correct when vertical axis is reversed and padding is used', + (WidgetTester tester) async { + // Regression test for https://github.com/flutter/flutter/issues/177117 + final tableView = TableView.builder( + verticalDetails: const ScrollableDetails.vertical(reverse: true), + rowCount: 1, + columnCount: 1, + columnBuilder: (int index) => + const TableSpan(extent: FixedTableSpanExtent(200.0)), + rowBuilder: (int index) => const TableSpan( + extent: FixedTableSpanExtent(200.0), + padding: TableSpanPadding(leading: 10.0, trailing: 20.0), + backgroundDecoration: TableSpanDecoration(color: Colors.red), + ), + cellBuilder: (_, TableVicinity vicinity) { + return TableViewCell( + child: Container(width: 200, height: 200, color: Colors.blue), + ); + }, + ); + + tester.view.physicalSize = const Size(400, 400); + tester.view.devicePixelRatio = 1.0; + addTearDown(() { + tester.view.resetPhysicalSize(); + tester.view.resetDevicePixelRatio(); + }); + + await tester.pumpWidget(MaterialApp(home: Scaffold(body: tableView))); + await tester.pumpAndSettle(); + + // Since vertical is reversed, row 0 is at the bottom (y=400). + // Leading padding covers from y=390 to y=400. + // Trailing padding covers from y=170 to y=190. + // Content covers from y=190 to y=390. + expect( + find.byType(TableViewport), + paints..rect( + rect: const Rect.fromLTRB(0.0, 170.0, 200.0, 400.0), + color: Colors.red, + ), + ); + }, + ); }); group('merged cell decorations', () { diff --git a/packages/two_dimensional_scrollables/test/table_view/table_test.dart b/packages/two_dimensional_scrollables/test/table_view/table_test.dart index 50ec9d4640db..a59a3301a778 100644 --- a/packages/two_dimensional_scrollables/test/table_view/table_test.dart +++ b/packages/two_dimensional_scrollables/test/table_view/table_test.dart @@ -4175,6 +4175,105 @@ void main() { ); }, ); + + testWidgets( + 'Table does not crash when focusing outside of the table while focused text field is not in the view', + (WidgetTester tester) async { + // Regression test for https://github.com/flutter/flutter/issues/137112 + final verticalController = ScrollController(); + final horizontalController = ScrollController(); + addTearDown(() { + verticalController.dispose(); + horizontalController.dispose(); + }); + + await tester.pumpWidget( + MaterialApp( + home: Scaffold( + body: Column( + children: [ + const TextField(key: Key('outside_textfield')), + Expanded( + child: TableView.builder( + verticalDetails: ScrollableDetails.vertical( + controller: verticalController, + ), + horizontalDetails: ScrollableDetails.horizontal( + controller: horizontalController, + ), + cellBuilder: + (BuildContext context, TableVicinity vicinity) { + return TableViewCell( + child: Center( + child: TextField( + key: Key( + 'cell_${vicinity.row}_${vicinity.column}', + ), + ), + ), + ); + }, + columnCount: 20, + columnBuilder: (int index) { + return const TableSpan( + foregroundDecoration: TableSpanDecoration( + border: TableSpanBorder(trailing: BorderSide()), + ), + extent: FixedTableSpanExtent(100), + ); + }, + rowCount: 40, + rowBuilder: (int index) { + return TableSpan( + backgroundDecoration: TableSpanDecoration( + color: index.isEven ? Colors.purple[100] : null, + border: const TableSpanBorder( + trailing: BorderSide(width: 3), + ), + ), + extent: const FixedTableSpanExtent(50), + ); + }, + ), + ), + ], + ), + ), + ), + ); + + // 1. Select a TextField in the table. + // Use the vicinity from the original crash report. + const vicinity = TableVicinity(row: 5, column: 6); + final Finder cellTextField = find.byKey( + Key('cell_${vicinity.row}_${vicinity.column}'), + ); + // Bring it into view. + verticalController.jumpTo(250); + horizontalController.jumpTo(600); + await tester.pumpAndSettle(); + + await tester.tap(cellTextField); + await tester.pumpAndSettle(); + expect(FocusManager.instance.primaryFocus, isNotNull); + + // 2. Scroll until it disappears from the view, without unfocusing it. + verticalController.jumpTo(verticalController.offset + 1000); + await tester.pumpAndSettle(); + + // 3. Select another TextField outside of the table. + final Finder outsideTextField = find.byKey( + const Key('outside_textfield'), + ); + await tester.tap(outsideTextField); + await tester.pumpAndSettle(); + + // 4. Scroll back and ensure the table does not crash. + verticalController.jumpTo(verticalController.offset - 1000); + await tester.pumpAndSettle(); + expect(cellTextField, findsOneWidget); + }, + ); } class _NullBuildContext implements BuildContext, TwoDimensionalChildManager { diff --git a/packages/two_dimensional_scrollables/test/tree_view/alignment_test.dart b/packages/two_dimensional_scrollables/test/tree_view/alignment_test.dart new file mode 100644 index 000000000000..9783e253309e --- /dev/null +++ b/packages/two_dimensional_scrollables/test/tree_view/alignment_test.dart @@ -0,0 +1,91 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter/widgets.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:two_dimensional_scrollables/two_dimensional_scrollables.dart'; + +void main() { + group('TreeView alignment', () { + testWidgets('Default alignment - topLeft', (WidgetTester tester) async { + final tree = >[TreeViewNode('Root')]; + + await tester.pumpWidget( + WidgetsApp( + color: const Color(0xFFFFFFFF), + debugShowCheckedModeBanner: false, + builder: (context, child) => Directionality( + textDirection: TextDirection.ltr, + child: Align( + alignment: Alignment.topLeft, + child: SizedBox( + width: 400, + height: 400, + child: TreeView( + tree: tree, + treeNodeBuilder: (context, node, toggleAnimationStyle) => + SizedBox( + key: const ValueKey('Root'), + height: 100, + child: Text(node.content), + ), + treeRowBuilder: (node) => + const TreeRow(extent: FixedTreeRowExtent(100)), + ), + ), + ), + ), + ), + ); + + final Offset treeTopLeft = tester.getTopLeft( + find.byType(TreeView), + ); + // Default is Alignment.topLeft (0, 0) + final Finder root = find.byKey(const ValueKey('Root')); + expect(tester.getTopLeft(root) - treeTopLeft, Offset.zero); + }); + + testWidgets('Vertical alignment - center', (WidgetTester tester) async { + const viewportHeight = 600.0; + final tree = >[TreeViewNode('Root')]; + + await tester.pumpWidget( + WidgetsApp( + color: const Color(0xFFFFFFFF), + debugShowCheckedModeBanner: false, + builder: (context, child) => Directionality( + textDirection: TextDirection.ltr, + child: Align( + alignment: Alignment.topLeft, + child: SizedBox( + width: 400, + height: viewportHeight, + child: TreeView( + tree: tree, + alignment: Alignment.center, + treeNodeBuilder: (context, node, toggleAnimationStyle) => + SizedBox( + key: const ValueKey('Root'), + height: 100, + child: Text(node.content), + ), + treeRowBuilder: (node) => + const TreeRow(extent: FixedTreeRowExtent(100)), + ), + ), + ), + ), + ), + ); + + final Offset treeTopLeft = tester.getTopLeft( + find.byType(TreeView), + ); + // Tree is 100 high, viewport is 600 high. Centered means 250 offset. + final Finder root = find.byKey(const ValueKey('Root')); + expect(tester.getTopLeft(root) - treeTopLeft, const Offset(0.0, 250.0)); + }); + }); +} diff --git a/packages/url_launcher/url_launcher_android/CHANGELOG.md b/packages/url_launcher/url_launcher_android/CHANGELOG.md index 09f2f425163c..2cb8a74f5f26 100644 --- a/packages/url_launcher/url_launcher_android/CHANGELOG.md +++ b/packages/url_launcher/url_launcher_android/CHANGELOG.md @@ -1,3 +1,7 @@ +## 6.3.29 + +* Updates build files from Groovy to Kotlin. + ## 6.3.28 * Bumps com.android.tools.build:gradle from 8.12.1 to 8.13.1. diff --git a/packages/url_launcher/url_launcher_android/android/build.gradle b/packages/url_launcher/url_launcher_android/android/build.gradle.kts similarity index 70% rename from packages/url_launcher/url_launcher_android/android/build.gradle rename to packages/url_launcher/url_launcher_android/android/build.gradle.kts index e77948ab280e..70044901998b 100644 --- a/packages/url_launcher/url_launcher_android/android/build.gradle +++ b/packages/url_launcher/url_launcher_android/android/build.gradle.kts @@ -12,19 +12,22 @@ buildscript { } } -rootProject.allprojects { +allprojects { repositories { google() mavenCentral() } } -apply plugin: 'com.android.library' +plugins { + id("com.android.library") +} android { buildFeatures { buildConfig = true } + namespace = "io.flutter.plugins.urllauncher" compileSdk = flutter.compileSdkVersion @@ -41,24 +44,25 @@ android { lint { checkAllWarnings = true warningsAsErrors = true - disable 'AndroidGradlePluginVersion', 'InvalidPackage', 'GradleDependency', 'NewerVersionAvailable' + disable.addAll(setOf("AndroidGradlePluginVersion", "InvalidPackage", "GradleDependency", "NewerVersionAvailable")) } testOptions { - unitTests.includeAndroidResources = true - unitTests.returnDefaultValues = true - unitTests.all { - testLogging { - events "passed", "skipped", "failed", "standardOut", "standardError" - outputs.upToDateWhen {false} - showStandardStreams = true + unitTests { + isIncludeAndroidResources = true + isReturnDefaultValues = true + all { + it.outputs.upToDateWhen { false } + it.testLogging { + events("passed", "skipped", "failed", "standardOut", "standardError") + showStandardStreams = true + } } } } } dependencies { - // Java language implementation implementation("androidx.core:core:1.17.0") implementation("androidx.annotation:annotation:1.9.1") diff --git a/packages/url_launcher/url_launcher_android/android/settings.gradle b/packages/url_launcher/url_launcher_android/android/settings.gradle deleted file mode 100644 index d8b7cc47172c..000000000000 --- a/packages/url_launcher/url_launcher_android/android/settings.gradle +++ /dev/null @@ -1 +0,0 @@ -rootProject.name = 'url_launcher_android' diff --git a/packages/url_launcher/url_launcher_android/android/settings.gradle.kts b/packages/url_launcher/url_launcher_android/android/settings.gradle.kts new file mode 100644 index 000000000000..22c54c2e0d72 --- /dev/null +++ b/packages/url_launcher/url_launcher_android/android/settings.gradle.kts @@ -0,0 +1 @@ +rootProject.name = "url_launcher_android" diff --git a/packages/url_launcher/url_launcher_android/pubspec.yaml b/packages/url_launcher/url_launcher_android/pubspec.yaml index 4aeab9b6eee2..425b261484ae 100644 --- a/packages/url_launcher/url_launcher_android/pubspec.yaml +++ b/packages/url_launcher/url_launcher_android/pubspec.yaml @@ -2,7 +2,7 @@ name: url_launcher_android description: Android implementation of the url_launcher plugin. repository: https://github.com/flutter/packages/tree/main/packages/url_launcher/url_launcher_android issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+url_launcher%22 -version: 6.3.28 +version: 6.3.29 environment: sdk: ^3.9.0 diff --git a/packages/video_player/video_player_android/CHANGELOG.md b/packages/video_player/video_player_android/CHANGELOG.md index 6b2fd16f7b83..f8e4cec20dcd 100644 --- a/packages/video_player/video_player_android/CHANGELOG.md +++ b/packages/video_player/video_player_android/CHANGELOG.md @@ -2,6 +2,10 @@ * Implements `getVideoTracks()` and `selectVideoTrack()` methods for video track (quality) selection using ExoPlayer. +## 2.9.5 + +* Updates build files from Groovy to Kotlin. + ## 2.9.4 * Updates `androidx.media3` to 1.9.2. diff --git a/packages/video_player/video_player_android/android/build.gradle b/packages/video_player/video_player_android/android/build.gradle.kts similarity index 54% rename from packages/video_player/video_player_android/android/build.gradle rename to packages/video_player/video_player_android/android/build.gradle.kts index 36d91037969e..4f7eccc4b4e4 100644 --- a/packages/video_player/video_player_android/android/build.gradle +++ b/packages/video_player/video_player_android/android/build.gradle.kts @@ -1,8 +1,10 @@ +import org.jetbrains.kotlin.gradle.dsl.JvmTarget + group = "io.flutter.plugins.videoplayer" version = "1.0-SNAPSHOT" buildscript { - ext.kotlin_version = '2.3.0' + val kotlinVersion = "2.3.0" repositories { google() mavenCentral() @@ -10,19 +12,27 @@ buildscript { dependencies { classpath("com.android.tools.build:gradle:8.13.1") - classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version") + classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion") } } -rootProject.allprojects { +allprojects { repositories { google() mavenCentral() } } -apply plugin: 'com.android.library' -apply plugin: 'kotlin-android' +plugins { + id("com.android.library") + id("kotlin-android") +} + +kotlin { + compilerOptions { + jvmTarget = JvmTarget.fromTarget(JavaVersion.VERSION_17.toString()) + } +} android { namespace = "io.flutter.plugins.videoplayer" @@ -36,7 +46,7 @@ android { lint { checkAllWarnings = true warningsAsErrors = true - disable 'AndroidGradlePluginVersion', 'InvalidPackage', 'GradleDependency', 'NewerVersionAvailable' + disable.addAll(setOf("AndroidGradlePluginVersion", "InvalidPackage", "GradleDependency", "NewerVersionAvailable")) baseline = file("lint-baseline.xml") } @@ -45,41 +55,35 @@ android { targetCompatibility = JavaVersion.VERSION_17 } - kotlinOptions { - jvmTarget = JavaVersion.VERSION_17.toString() - } - - sourceSets { - main.java.srcDirs += 'src/main/kotlin' - } - dependencies { - def exoplayer_version = "1.9.2" - implementation("androidx.media3:media3-exoplayer:${exoplayer_version}") - implementation("androidx.media3:media3-exoplayer-hls:${exoplayer_version}") - implementation("androidx.media3:media3-exoplayer-dash:${exoplayer_version}") - implementation("androidx.media3:media3-exoplayer-rtsp:${exoplayer_version}") - implementation("androidx.media3:media3-exoplayer-smoothstreaming:${exoplayer_version}") + val exoplayerVersion = "1.9.2" + implementation("androidx.media3:media3-exoplayer:${exoplayerVersion}") + implementation("androidx.media3:media3-exoplayer-hls:${exoplayerVersion}") + implementation("androidx.media3:media3-exoplayer-dash:${exoplayerVersion}") + implementation("androidx.media3:media3-exoplayer-rtsp:${exoplayerVersion}") + implementation("androidx.media3:media3-exoplayer-smoothstreaming:${exoplayerVersion}") testImplementation("junit:junit:4.13.2") testImplementation("androidx.test:core:1.7.0") testImplementation("org.mockito:mockito-core:5.23.0") testImplementation("org.robolectric:robolectric:4.16") - testImplementation("androidx.media3:media3-test-utils:${exoplayer_version}") + testImplementation("androidx.media3:media3-test-utils:${exoplayerVersion}") } testOptions { - unitTests.includeAndroidResources = true - unitTests.returnDefaultValues = true - unitTests.all { - // The org.gradle.jvmargs property that may be set in gradle.properties does not impact - // the Java heap size when running the Android unit tests. The following property here - // sets the heap size to a size large enough to run the robolectric tests across - // multiple SDK levels. - jvmArgs "-Xmx4G" - testLogging { - events "passed", "skipped", "failed", "standardOut", "standardError" - outputs.upToDateWhen {false} - showStandardStreams = true + unitTests { + isIncludeAndroidResources = true + isReturnDefaultValues = true + all { + it.outputs.upToDateWhen { false } + it.testLogging { + events("passed", "skipped", "failed", "standardOut", "standardError") + showStandardStreams = true + } + // The org.gradle.jvmargs property that may be set in gradle.properties does not impact + // the Java heap size when running the Android unit tests. The following property here + // sets the heap size to a size large enough to run the robolectric tests across + // multiple SDK levels. + it.jvmArgs("-Xmx4G") } } } diff --git a/packages/video_player/video_player_android/android/settings.gradle b/packages/video_player/video_player_android/android/settings.gradle deleted file mode 100644 index 00681714f7d8..000000000000 --- a/packages/video_player/video_player_android/android/settings.gradle +++ /dev/null @@ -1 +0,0 @@ -rootProject.name = 'video_player_android' diff --git a/packages/video_player/video_player_android/android/settings.gradle.kts b/packages/video_player/video_player_android/android/settings.gradle.kts new file mode 100644 index 000000000000..e3289a056828 --- /dev/null +++ b/packages/video_player/video_player_android/android/settings.gradle.kts @@ -0,0 +1 @@ +rootProject.name = "video_player_android" diff --git a/packages/video_player/video_player_android/pubspec.yaml b/packages/video_player/video_player_android/pubspec.yaml index 7078e42a0ab1..9a78bee27422 100644 --- a/packages/video_player/video_player_android/pubspec.yaml +++ b/packages/video_player/video_player_android/pubspec.yaml @@ -2,7 +2,7 @@ name: video_player_android description: Android implementation of the video_player plugin. repository: https://github.com/flutter/packages/tree/main/packages/video_player/video_player_android issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+video_player%22 -version: 2.9.4 +version: 2.9.5 environment: sdk: ^3.9.0 diff --git a/packages/webview_flutter/webview_flutter_android/CHANGELOG.md b/packages/webview_flutter/webview_flutter_android/CHANGELOG.md index 088dcb547c3e..92357d7a3e36 100644 --- a/packages/webview_flutter/webview_flutter_android/CHANGELOG.md +++ b/packages/webview_flutter/webview_flutter_android/CHANGELOG.md @@ -1,3 +1,11 @@ +## 4.10.15 + +* Fixes dartdoc comments that accidentally used HTML. + +## 4.10.14 + +* Updates build files from Groovy to Kotlin. + ## 4.10.13 * Bumps androidx.webkit:webkit from 1.14.0 to 1.15.0. diff --git a/packages/webview_flutter/webview_flutter_android/android/build.gradle b/packages/webview_flutter/webview_flutter_android/android/build.gradle.kts similarity index 62% rename from packages/webview_flutter/webview_flutter_android/android/build.gradle rename to packages/webview_flutter/webview_flutter_android/android/build.gradle.kts index 9a14dfe32220..6872533d581d 100644 --- a/packages/webview_flutter/webview_flutter_android/android/build.gradle +++ b/packages/webview_flutter/webview_flutter_android/android/build.gradle.kts @@ -1,8 +1,10 @@ +import org.jetbrains.kotlin.gradle.dsl.JvmTarget + group = "io.flutter.plugins.webviewflutter" version = "1.0-SNAPSHOT" buildscript { - ext.kotlin_version = '2.3.0' + val kotlinVersion = "2.3.0" repositories { google() mavenCentral() @@ -10,19 +12,27 @@ buildscript { dependencies { classpath("com.android.tools.build:gradle:8.13.1") - classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version") + classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion") } } -rootProject.allprojects { +allprojects { repositories { google() mavenCentral() } } -apply plugin: 'com.android.library' -apply plugin: 'kotlin-android' +plugins { + id("com.android.library") + id("kotlin-android") +} + +kotlin { + compilerOptions { + jvmTarget = JvmTarget.fromTarget(JavaVersion.VERSION_17.toString()) + } +} android { namespace = "io.flutter.plugins.webviewflutter" @@ -33,10 +43,6 @@ android { targetCompatibility = JavaVersion.VERSION_17 } - kotlinOptions { - jvmTarget = JavaVersion.VERSION_17.toString() - } - defaultConfig { minSdk = 24 testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" @@ -45,7 +51,7 @@ android { lint { checkAllWarnings = true warningsAsErrors = true - disable 'AndroidGradlePluginVersion', 'InvalidPackage', 'GradleDependency', 'NewerVersionAvailable' + disable.addAll(setOf("AndroidGradlePluginVersion", "InvalidPackage", "GradleDependency", "NewerVersionAvailable")) baseline = file("lint-baseline.xml") } @@ -59,13 +65,15 @@ android { } testOptions { - unitTests.includeAndroidResources = true - unitTests.returnDefaultValues = true - unitTests.all { - testLogging { - events "passed", "skipped", "failed", "standardOut", "standardError" - outputs.upToDateWhen {false} - showStandardStreams = true + unitTests { + isIncludeAndroidResources = true + isReturnDefaultValues = true + all { + it.outputs.upToDateWhen { false } + it.testLogging { + events("passed", "skipped", "failed", "standardOut", "standardError") + showStandardStreams = true + } } } } diff --git a/packages/webview_flutter/webview_flutter_android/android/settings.gradle b/packages/webview_flutter/webview_flutter_android/android/settings.gradle deleted file mode 100644 index 5be7a4b4c692..000000000000 --- a/packages/webview_flutter/webview_flutter_android/android/settings.gradle +++ /dev/null @@ -1 +0,0 @@ -rootProject.name = 'webview_flutter' diff --git a/packages/webview_flutter/webview_flutter_android/android/settings.gradle.kts b/packages/webview_flutter/webview_flutter_android/android/settings.gradle.kts new file mode 100644 index 000000000000..009a3e185c9a --- /dev/null +++ b/packages/webview_flutter/webview_flutter_android/android/settings.gradle.kts @@ -0,0 +1 @@ +rootProject.name = "webview_flutter" diff --git a/packages/webview_flutter/webview_flutter_android/example/lib/legacy/web_view.dart b/packages/webview_flutter/webview_flutter_android/example/lib/legacy/web_view.dart index 5b40feac0142..06ecd148e869 100644 --- a/packages/webview_flutter/webview_flutter_android/example/lib/legacy/web_view.dart +++ b/packages/webview_flutter/webview_flutter_android/example/lib/legacy/web_view.dart @@ -202,7 +202,7 @@ class WebView extends StatefulWidget { /// /// To debug WebViews on iOS: /// - Enable developer options (Open Safari, go to Preferences -> Advanced and make sure "Show Develop Menu in Menubar" is on.) - /// - From the Menu-bar (of Safari) select Develop -> iPhone Simulator -> + /// - From the Menu-bar (of Safari) select Develop -> iPhone Simulator -> your webview page /// /// By default `debuggingEnabled` is false. final bool debuggingEnabled; diff --git a/packages/webview_flutter/webview_flutter_android/pubspec.yaml b/packages/webview_flutter/webview_flutter_android/pubspec.yaml index 4415fcfbbaee..30ff682994ac 100644 --- a/packages/webview_flutter/webview_flutter_android/pubspec.yaml +++ b/packages/webview_flutter/webview_flutter_android/pubspec.yaml @@ -2,7 +2,7 @@ name: webview_flutter_android description: A Flutter plugin that provides a WebView widget on Android. repository: https://github.com/flutter/packages/tree/main/packages/webview_flutter/webview_flutter_android issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+webview%22 -version: 4.10.13 +version: 4.10.15 environment: sdk: ^3.9.0 diff --git a/packages/webview_flutter/webview_flutter_platform_interface/CHANGELOG.md b/packages/webview_flutter/webview_flutter_platform_interface/CHANGELOG.md index cc16a26cb2f3..72e84d87c3d1 100644 --- a/packages/webview_flutter/webview_flutter_platform_interface/CHANGELOG.md +++ b/packages/webview_flutter/webview_flutter_platform_interface/CHANGELOG.md @@ -1,5 +1,10 @@ -## NEXT +## 2.15.1 +* Fixes dartdoc comments that accidentally used HTML. + +## 2.15.0 + +* Adds support to retrieve WebView cookies. See `PlatformWebViewCookieManager.getCookies`. * Updates minimum supported SDK version to Flutter 3.35/Dart 3.9. ## 2.14.0 diff --git a/packages/webview_flutter/webview_flutter_platform_interface/lib/src/legacy/types/webview_cookie.dart b/packages/webview_flutter/webview_flutter_platform_interface/lib/src/legacy/types/webview_cookie.dart index 022d8d63821c..aae8984a9089 100644 --- a/packages/webview_flutter/webview_flutter_platform_interface/lib/src/legacy/types/webview_cookie.dart +++ b/packages/webview_flutter/webview_flutter_platform_interface/lib/src/legacy/types/webview_cookie.dart @@ -38,7 +38,7 @@ class WebViewCookie { /// https://datatracker.ietf.org/doc/html/draft-ietf-httpbis-rfc6265bis-02#section-4.1.1 final String path; - /// Serializes the [WebViewCookie] to a Map. + /// Serializes the [WebViewCookie] to a `Map`. Map toJson() { return { 'name': name, diff --git a/packages/webview_flutter/webview_flutter_platform_interface/lib/src/platform_webview_cookie_manager.dart b/packages/webview_flutter/webview_flutter_platform_interface/lib/src/platform_webview_cookie_manager.dart index 112b85e12568..6368ce7fdb7a 100644 --- a/packages/webview_flutter/webview_flutter_platform_interface/lib/src/platform_webview_cookie_manager.dart +++ b/packages/webview_flutter/webview_flutter_platform_interface/lib/src/platform_webview_cookie_manager.dart @@ -64,4 +64,12 @@ abstract class PlatformWebViewCookieManager extends PlatformInterface { 'setCookie is not implemented on the current platform', ); } + + /// Returns a list of existing cookies for the specified domain from all + /// [WebView] instances of the application. + Future> getCookies(Uri url) { + throw UnimplementedError( + 'getCookies is not implemented on the current platform', + ); + } } diff --git a/packages/webview_flutter/webview_flutter_platform_interface/lib/src/types/webview_cookie.dart b/packages/webview_flutter/webview_flutter_platform_interface/lib/src/types/webview_cookie.dart index 026f2d6c6e02..1ab8e0867a17 100644 --- a/packages/webview_flutter/webview_flutter_platform_interface/lib/src/types/webview_cookie.dart +++ b/packages/webview_flutter/webview_flutter_platform_interface/lib/src/types/webview_cookie.dart @@ -38,4 +38,9 @@ class WebViewCookie { /// Its value should match "path-value" in RFC6265bis: /// https://datatracker.ietf.org/doc/html/draft-ietf-httpbis-rfc6265bis-02#section-4.1.1 final String path; + + @override + String toString() { + return 'WebViewCookie{name: $name, value: $value, domain: $domain, path: $path}'; + } } diff --git a/packages/webview_flutter/webview_flutter_platform_interface/pubspec.yaml b/packages/webview_flutter/webview_flutter_platform_interface/pubspec.yaml index 2b755499a9d2..6528399fd0e0 100644 --- a/packages/webview_flutter/webview_flutter_platform_interface/pubspec.yaml +++ b/packages/webview_flutter/webview_flutter_platform_interface/pubspec.yaml @@ -4,7 +4,7 @@ repository: https://github.com/flutter/packages/tree/main/packages/webview_flutt issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+webview_flutter%22 # NOTE: We strongly prefer non-breaking changes, even at the expense of a # less-clean API. See https://flutter.dev/go/platform-interface-breaking-changes -version: 2.14.0 +version: 2.15.1 environment: sdk: ^3.9.0 diff --git a/packages/webview_flutter/webview_flutter_platform_interface/test/platform_webview_cookie_manager_test.dart b/packages/webview_flutter/webview_flutter_platform_interface/test/platform_webview_cookie_manager_test.dart new file mode 100644 index 000000000000..471bdfbbd085 --- /dev/null +++ b/packages/webview_flutter/webview_flutter_platform_interface/test/platform_webview_cookie_manager_test.dart @@ -0,0 +1,125 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter_test/flutter_test.dart'; +import 'package:mockito/mockito.dart'; +import 'package:plugin_platform_interface/plugin_platform_interface.dart'; +import 'package:webview_flutter_platform_interface/webview_flutter_platform_interface.dart'; + +import 'webview_platform_test.mocks.dart'; + +void main() { + setUp(() { + WebViewPlatform.instance = MockWebViewPlatformWithMixin(); + }); + + test('Cannot be implemented with `implements`', () { + when( + (WebViewPlatform.instance! as MockWebViewPlatform) + .createPlatformCookieManager(any), + ).thenReturn(ImplementsPlatformWebViewCookieManager()); + + expect(() { + PlatformWebViewCookieManager( + const PlatformWebViewCookieManagerCreationParams(), + ); + // In versions of `package:plugin_platform_interface` prior to fixing + // https://github.com/flutter/flutter/issues/109339, an attempt to + // implement a platform interface using `implements` would sometimes throw + // a `NoSuchMethodError` and other times throw an `AssertionError`. After + // the issue is fixed, an `AssertionError` will always be thrown. For the + // purpose of this test, we don't really care what exception is thrown, so + // just allow any exception. + }, throwsA(anything)); + }); + + test('Can be extended', () { + const params = PlatformWebViewCookieManagerCreationParams(); + when( + (WebViewPlatform.instance! as MockWebViewPlatform) + .createPlatformCookieManager(any), + ).thenReturn(ExtendsPlatformWebViewCookieManager(params)); + + expect(PlatformWebViewCookieManager(params), isNotNull); + }); + + test('Can be mocked with `implements`', () { + when( + (WebViewPlatform.instance! as MockWebViewPlatform) + .createPlatformCookieManager(any), + ).thenReturn(MockWebViewCookieManagerDelegate()); + + expect( + PlatformWebViewCookieManager( + const PlatformWebViewCookieManagerCreationParams(), + ), + isNotNull, + ); + }); + + test( + 'Default implementation of clearCookies should throw unimplemented error', + () { + final PlatformWebViewCookieManager cookieManager = + ExtendsPlatformWebViewCookieManager( + const PlatformWebViewCookieManagerCreationParams(), + ); + + expect(() => cookieManager.clearCookies(), throwsUnimplementedError); + }, + ); + + test( + 'Default implementation of setCookie should throw unimplemented error', + () { + final PlatformWebViewCookieManager cookieManager = + ExtendsPlatformWebViewCookieManager( + const PlatformWebViewCookieManagerCreationParams(), + ); + + expect( + () => cookieManager.setCookie( + const WebViewCookie(name: 'foo', value: 'bar', domain: 'flutter.dev'), + ), + throwsUnimplementedError, + ); + }, + ); + + test( + 'Default implementation of getCookies should throw unimplemented error', + () { + final PlatformWebViewCookieManager cookieManager = + ExtendsPlatformWebViewCookieManager( + const PlatformWebViewCookieManagerCreationParams(), + ); + + expect( + () => cookieManager.getCookies(Uri.parse('https://flutter.dev')), + throwsUnimplementedError, + ); + }, + ); +} + +class MockWebViewPlatformWithMixin extends MockWebViewPlatform + with + // ignore: prefer_mixin + MockPlatformInterfaceMixin {} + +class ImplementsPlatformWebViewCookieManager + implements PlatformWebViewCookieManager { + @override + dynamic noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation); +} + +class MockWebViewCookieManagerDelegate extends Mock + with + // ignore: prefer_mixin + MockPlatformInterfaceMixin + implements PlatformWebViewCookieManager {} + +class ExtendsPlatformWebViewCookieManager extends PlatformWebViewCookieManager { + ExtendsPlatformWebViewCookieManager(super.params) : super.implementation(); +} diff --git a/packages/webview_flutter/webview_flutter_wkwebview/CHANGELOG.md b/packages/webview_flutter/webview_flutter_wkwebview/CHANGELOG.md index 5a4511008367..efaab280aef5 100644 --- a/packages/webview_flutter/webview_flutter_wkwebview/CHANGELOG.md +++ b/packages/webview_flutter/webview_flutter_wkwebview/CHANGELOG.md @@ -1,3 +1,7 @@ +## 3.24.2 + +* Fixes dartdoc comments that accidentally used HTML. + ## 3.24.1 * Updates platform views on iOS to only have a weak reference to the native view. This is a diff --git a/packages/webview_flutter/webview_flutter_wkwebview/darwin/Tests/FWFWebViewFlutterWKWebViewExternalAPITests.swift b/packages/webview_flutter/webview_flutter_wkwebview/darwin/Tests/FWFWebViewFlutterWKWebViewExternalAPITests.swift index aa458aa30cda..0e28185185cd 100644 --- a/packages/webview_flutter/webview_flutter_wkwebview/darwin/Tests/FWFWebViewFlutterWKWebViewExternalAPITests.swift +++ b/packages/webview_flutter/webview_flutter_wkwebview/darwin/Tests/FWFWebViewFlutterWKWebViewExternalAPITests.swift @@ -97,71 +97,69 @@ class TestFlutterTextureRegistry: NSObject, FlutterTextureRegistry { } } -// TODO(stuartmorgan): This is temporarily disabled on iOS in favor of Stubs.h/m, -// because FlutterSceneLifeCycleDelegate isn't available on stable, and Swift doesn't -// allow using looser types (like Any) for protocol conformance. Once that -// protocol reaches stable, this #if should be removed, as should Stubs.*. -#if os(macOS) - class TestFlutterPluginRegistrar: NSObject, FlutterPluginRegistrar { - var plugin: WebViewFlutterPlugin? = nil +class TestFlutterPluginRegistrar: NSObject, FlutterPluginRegistrar { + var plugin: WebViewFlutterPlugin? = nil - #if os(iOS) - var viewController: UIViewController? - - func messenger() -> FlutterBinaryMessenger { - return TestBinaryMessenger() - } + #if os(iOS) + var viewController: UIViewController? - func textures() -> FlutterTextureRegistry { - return TestFlutterTextureRegistry() - } + func messenger() -> FlutterBinaryMessenger { + return TestBinaryMessenger() + } - func addApplicationDelegate(_ delegate: FlutterPlugin) { + func textures() -> FlutterTextureRegistry { + return TestFlutterTextureRegistry() + } - } + func addApplicationDelegate(_ delegate: FlutterPlugin) { - func register( - _ factory: FlutterPlatformViewFactory, withId factoryId: String, - gestureRecognizersBlockingPolicy: FlutterPlatformViewGestureRecognizersBlockingPolicy - ) { - } + } - func addSceneDelegate(_ delegate: any FlutterSceneLifeCycleDelegate) { - } - #elseif os(macOS) - var view: NSView? - var viewController: NSViewController? + func register( + _ factory: FlutterPlatformViewFactory, withId factoryId: String, + gestureRecognizersBlockingPolicy: FlutterPlatformViewGestureRecognizersBlockingPolicy + ) { + } - var messenger: FlutterBinaryMessenger { - return TestBinaryMessenger() - } + func addSceneDelegate(_ delegate: any FlutterSceneLifeCycleDelegate) { + } + #elseif os(macOS) + var view: NSView? + var viewController: NSViewController? - var textures: FlutterTextureRegistry { - return TestFlutterTextureRegistry() - } + var messenger: FlutterBinaryMessenger { + return TestBinaryMessenger() + } - func addApplicationDelegate(_ delegate: FlutterAppLifecycleDelegate) { + var textures: FlutterTextureRegistry { + return TestFlutterTextureRegistry() + } - } - #endif + func addApplicationDelegate(_ delegate: FlutterAppLifecycleDelegate) { - func register(_ factory: FlutterPlatformViewFactory, withId factoryId: String) { } + #endif - func publish(_ value: NSObject) { - plugin = (value as! WebViewFlutterPlugin) - } + func register(_ factory: FlutterPlatformViewFactory, withId factoryId: String) { + } - func addMethodCallDelegate(_ delegate: FlutterPlugin, channel: FlutterMethodChannel) { + func publish(_ value: NSObject) { + plugin = (value as! WebViewFlutterPlugin) + } - } + func addMethodCallDelegate(_ delegate: FlutterPlugin, channel: FlutterMethodChannel) { - func lookupKey(forAsset asset: String) -> String { - return "" - } + } - func lookupKey(forAsset asset: String, fromPackage package: String) -> String { - return "" - } + func lookupKey(forAsset asset: String) -> String { + return "" } -#endif + + func lookupKey(forAsset asset: String, fromPackage package: String) -> String { + return "" + } + + func valuePublished(byPlugin: String) -> NSObject? { + return nil + } +} diff --git a/packages/webview_flutter/webview_flutter_wkwebview/example/ios/Runner.xcodeproj/project.pbxproj b/packages/webview_flutter/webview_flutter_wkwebview/example/ios/Runner.xcodeproj/project.pbxproj index 39f911e5915c..e894f75ea1f8 100644 --- a/packages/webview_flutter/webview_flutter_wkwebview/example/ios/Runner.xcodeproj/project.pbxproj +++ b/packages/webview_flutter/webview_flutter_wkwebview/example/ios/Runner.xcodeproj/project.pbxproj @@ -8,7 +8,6 @@ /* Begin PBXBuildFile section */ 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; - 33C8DADB2E8D711500A9B7CA /* TemporaryObjCStub.m in Sources */ = {isa = PBXBuildFile; fileRef = 33C8DADA2E8D711500A9B7CA /* TemporaryObjCStub.m */; }; 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; 78A318202AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage in Frameworks */ = {isa = PBXBuildFile; productRef = 78A3181F2AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage */; }; 8F0E23522EEB5D6B002AB342 /* ColorProxyAPITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8F0E23512EEB5D6B002AB342 /* ColorProxyAPITests.swift */; }; @@ -88,8 +87,6 @@ /* Begin PBXFileReference section */ 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; - 33C8DAD92E8D711500A9B7CA /* TemporaryObjCStub.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TemporaryObjCStub.h; sourceTree = ""; }; - 33C8DADA2E8D711500A9B7CA /* TemporaryObjCStub.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TemporaryObjCStub.m; sourceTree = ""; }; 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; 68BDCAE923C3F7CB00D9C032 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 68BDCAED23C3F7CB00D9C032 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; @@ -131,7 +128,6 @@ 8F1488E02D2DE27000191744 /* WebViewConfigurationProxyAPITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = WebViewConfigurationProxyAPITests.swift; path = ../../darwin/Tests/WebViewConfigurationProxyAPITests.swift; sourceTree = SOURCE_ROOT; }; 8F1488E12D2DE27000191744 /* WebViewProxyAPITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = WebViewProxyAPITests.swift; path = ../../darwin/Tests/WebViewProxyAPITests.swift; sourceTree = SOURCE_ROOT; }; 8F1489002D2DE91C00191744 /* AuthenticationChallengeResponseProxyAPITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = AuthenticationChallengeResponseProxyAPITests.swift; path = ../../darwin/Tests/AuthenticationChallengeResponseProxyAPITests.swift; sourceTree = SOURCE_ROOT; }; - 8F66D9D72D1362BE000835F9 /* RunnerTests-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "RunnerTests-Bridging-Header.h"; sourceTree = ""; }; 8FEC64812DA2C6DC00C48569 /* GetTrustResultResponseProxyAPITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = GetTrustResultResponseProxyAPITests.swift; path = ../../darwin/Tests/GetTrustResultResponseProxyAPITests.swift; sourceTree = SOURCE_ROOT; }; 8FEC64822DA2C6DC00C48569 /* SecCertificateProxyAPITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = SecCertificateProxyAPITests.swift; path = ../../darwin/Tests/SecCertificateProxyAPITests.swift; sourceTree = SOURCE_ROOT; }; 8FEC64832DA2C6DC00C48569 /* SecTrustProxyAPITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = SecTrustProxyAPITests.swift; path = ../../darwin/Tests/SecTrustProxyAPITests.swift; sourceTree = SOURCE_ROOT; }; @@ -179,8 +175,6 @@ isa = PBXGroup; children = ( 8F0E23512EEB5D6B002AB342 /* ColorProxyAPITests.swift */, - 33C8DAD92E8D711500A9B7CA /* TemporaryObjCStub.h */, - 33C8DADA2E8D711500A9B7CA /* TemporaryObjCStub.m */, 8F0EDFD22E1F4967001938E6 /* ProxyAPIRegistrarTests.swift */, 8FEC64812DA2C6DC00C48569 /* GetTrustResultResponseProxyAPITests.swift */, 8FEC64822DA2C6DC00C48569 /* SecCertificateProxyAPITests.swift */, @@ -217,7 +211,6 @@ 8F1488E02D2DE27000191744 /* WebViewConfigurationProxyAPITests.swift */, 8F1488E12D2DE27000191744 /* WebViewProxyAPITests.swift */, 68BDCAED23C3F7CB00D9C032 /* Info.plist */, - 8F66D9D72D1362BE000835F9 /* RunnerTests-Bridging-Header.h */, ); path = RunnerTests; sourceTree = ""; @@ -397,7 +390,7 @@ ); mainGroup = 97C146E51CF9000F007C117D; packageReferences = ( - 781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "FlutterGeneratedPluginSwiftPackage" */, + 781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage" */, ); productRefGroup = 97C146EF1CF9000F007C117D /* Products */; projectDirPath = ""; @@ -493,7 +486,6 @@ 8F1488EC2D2DE27000191744 /* FrameInfoProxyAPITests.swift in Sources */, 8F1488ED2D2DE27000191744 /* ErrorProxyAPITests.swift in Sources */, 8F1488EE2D2DE27000191744 /* NSObjectProxyAPITests.swift in Sources */, - 33C8DADB2E8D711500A9B7CA /* TemporaryObjCStub.m in Sources */, 8F1488EF2D2DE27000191744 /* NavigationResponseProxyAPITests.swift in Sources */, 8FEC64852DA2C6DC00C48569 /* GetTrustResultResponseProxyAPITests.swift in Sources */, 8FEC64862DA2C6DC00C48569 /* WebpagePreferencesProxyAPITests.swift in Sources */, @@ -584,7 +576,6 @@ ); PRODUCT_BUNDLE_IDENTIFIER = dev.flutter.plugins.RunnerTests; PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_OBJC_BRIDGING_HEADER = "RunnerTests/RunnerTests-Bridging-Header.h"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 5.0; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/Runner"; @@ -607,7 +598,6 @@ PRODUCT_BUNDLE_IDENTIFIER = dev.flutter.plugins.RunnerTests; PRODUCT_NAME = "$(TARGET_NAME)"; SUPPORTED_PLATFORMS = "iphonesimulator iphoneos"; - SWIFT_OBJC_BRIDGING_HEADER = "RunnerTests/RunnerTests-Bridging-Header.h"; SWIFT_VERSION = 5.0; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/Runner"; USE_HEADERMAP = NO; @@ -861,7 +851,7 @@ /* End XCConfigurationList section */ /* Begin XCLocalSwiftPackageReference section */ - 781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "FlutterGeneratedPluginSwiftPackage" */ = { + 781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage" */ = { isa = XCLocalSwiftPackageReference; relativePath = Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage; }; diff --git a/packages/webview_flutter/webview_flutter_wkwebview/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/packages/webview_flutter/webview_flutter_wkwebview/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index ef4558defd55..03bd8e4ad04b 100644 --- a/packages/webview_flutter/webview_flutter_wkwebview/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/packages/webview_flutter/webview_flutter_wkwebview/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -44,6 +44,7 @@ buildConfiguration = "Debug" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" + customLLDBInitFile = "$(SRCROOT)/Flutter/ephemeral/flutter_lldbinit" shouldUseLaunchSchemeArgsEnv = "YES"> - -@property(nonatomic, nullable) NSObject *plugin; -@property(nonatomic, weak, nullable) UIViewController *viewController; - -@end - -NS_ASSUME_NONNULL_END - -#endif diff --git a/packages/webview_flutter/webview_flutter_wkwebview/example/ios/RunnerTests/TemporaryObjCStub.m b/packages/webview_flutter/webview_flutter_wkwebview/example/ios/RunnerTests/TemporaryObjCStub.m deleted file mode 100644 index 2e8704e46aef..000000000000 --- a/packages/webview_flutter/webview_flutter_wkwebview/example/ios/RunnerTests/TemporaryObjCStub.m +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright 2013 The Flutter Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -@import Foundation; - -// TODO(stuartmorgan): This file is temporarily iOS workaround for changes in -// FlutterPluginRegistrar. See the TestFlutterPluginRegistrar TODO in -// FWFWebViewFlutterWKWebViewExternalAPITests.swift. -#if TARGET_OS_IOS - -#import "TemporaryObjCStub.h" -@import Flutter; - -#import "RunnerTests-Swift.h" - -// This FlutterPluginRegistrar is a protocol, so to make a stub it has to be implemented. -@implementation TestFlutterPluginRegistrar - -- (void)addApplicationDelegate:(nonnull NSObject *)delegate { -} - -- (void)addMethodCallDelegate:(nonnull NSObject *)delegate - channel:(nonnull FlutterMethodChannel *)channel { -} - -- (nonnull NSString *)lookupKeyForAsset:(nonnull NSString *)asset { - return @""; -} - -- (nonnull NSString *)lookupKeyForAsset:(nonnull NSString *)asset - fromPackage:(nonnull NSString *)package { - return @""; -} - -- (nonnull NSObject *)messenger { - return [[TestBinaryMessenger alloc] init]; -} - -- (void)publish:(nonnull NSObject *)value { - self.plugin = value; -} - -- (void)registerViewFactory:(nonnull NSObject *)factory - withId:(nonnull NSString *)factoryId { -} - -- (void)registerViewFactory:(nonnull NSObject *)factory - withId:(nonnull NSString *)factoryId - gestureRecognizersBlockingPolicy: - (FlutterPlatformViewGestureRecognizersBlockingPolicy)gestureRecognizersBlockingPolicy { -} - -- (nonnull NSObject *)textures { - return [[TestFlutterTextureRegistry alloc] init]; -} - -// This would be NSObject, but -// FlutterSceneLifeCycleDelegate is not available on stable. -- (void)addSceneDelegate:(nonnull NSObject *)delegate { -} - -@end - -#endif diff --git a/packages/webview_flutter/webview_flutter_wkwebview/example/lib/legacy/web_view.dart b/packages/webview_flutter/webview_flutter_wkwebview/example/lib/legacy/web_view.dart index cd98cb6119e4..ebf848c1b58a 100644 --- a/packages/webview_flutter/webview_flutter_wkwebview/example/lib/legacy/web_view.dart +++ b/packages/webview_flutter/webview_flutter_wkwebview/example/lib/legacy/web_view.dart @@ -193,7 +193,7 @@ class WebView extends StatefulWidget { /// /// To debug WebViews on iOS: /// - Enable developer options (Open Safari, go to Preferences -> Advanced and make sure "Show Develop Menu in Menubar" is on.) - /// - From the Menu-bar (of Safari) select Develop -> iPhone Simulator -> + /// - From the Menu-bar (of Safari) select Develop -> iPhone Simulator -> your webview page /// /// By default `debuggingEnabled` is false. final bool debuggingEnabled; diff --git a/packages/webview_flutter/webview_flutter_wkwebview/pubspec.yaml b/packages/webview_flutter/webview_flutter_wkwebview/pubspec.yaml index d61c43b4012a..7330bbae7e60 100644 --- a/packages/webview_flutter/webview_flutter_wkwebview/pubspec.yaml +++ b/packages/webview_flutter/webview_flutter_wkwebview/pubspec.yaml @@ -2,7 +2,7 @@ name: webview_flutter_wkwebview description: A Flutter plugin that provides a WebView widget based on Apple's WKWebView control. repository: https://github.com/flutter/packages/tree/main/packages/webview_flutter/webview_flutter_wkwebview issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+webview%22 -version: 3.24.1 +version: 3.24.2 environment: sdk: ^3.9.0 diff --git a/script/tool/lib/src/common/file_filters.dart b/script/tool/lib/src/common/file_filters.dart index 7a1bafd06a5c..90be24da8d03 100644 --- a/script/tool/lib/src/common/file_filters.dart +++ b/script/tool/lib/src/common/file_filters.dart @@ -9,10 +9,10 @@ bool isRepoLevelNonCodeImpactingFile(String path) { return [ 'AUTHORS', - 'CODEOWNERS', 'CONTRIBUTING.md', 'LICENSE', 'README.md', + 'SUGGESTED_REVIEWERS.md', 'AGENTS.md', // This deliberate lists specific files rather than excluding the whole // .github directory since it's better to have false negatives than to diff --git a/script/tool/lib/src/common/package_command.dart b/script/tool/lib/src/common/package_command.dart index 77f91c069bbf..838256acb7e0 100644 --- a/script/tool/lib/src/common/package_command.dart +++ b/script/tool/lib/src/common/package_command.dart @@ -253,27 +253,27 @@ abstract class PackageCommand extends Command { return gitDir; } - /// Convenience accessor for boolean arguments. + /// Convenience accessor for `bool` arguments. bool getBoolArg(String key) { return (argResults![key] as bool?) ?? false; } - /// Convenience accessor for boolean arguments. + /// Convenience accessor for nullable `bool` arguments. bool? getNullableBoolArg(String key) { return argResults![key] as bool?; } - /// Convenience accessor for String arguments. + /// Convenience accessor for `String` arguments. String getStringArg(String key) { return (argResults![key] as String?) ?? ''; } - /// Convenience accessor for String arguments. + /// Convenience accessor for nullable `String` arguments. String? getNullableStringArg(String key) { return argResults![key] as String?; } - /// Convenience accessor for List arguments. + /// Convenience accessor for `List` arguments. List getStringListArg(String key) { // Clone the list so that if a caller modifies the result it won't change // the actual arguments list for future queries. diff --git a/script/tool/lib/src/publish_command.dart b/script/tool/lib/src/publish_command.dart index d043da0a60c3..c45d847b3d19 100644 --- a/script/tool/lib/src/publish_command.dart +++ b/script/tool/lib/src/publish_command.dart @@ -39,7 +39,7 @@ class _RemoteInfo { /// /// 1. Checks for any modified files in git and refuses to publish if there's an /// issue. -/// 2. Tags the release with the format -v. +/// 2. Tags the release with the format `-v`. /// 3. Pushes the release to a remote. /// /// Both 2 and 3 are optional, see `plugin_tools help publish` for full diff --git a/script/tool/lib/src/repo_package_info_check_command.dart b/script/tool/lib/src/repo_package_info_check_command.dart index c423d760ea85..1c213fd2d0f3 100644 --- a/script/tool/lib/src/repo_package_info_check_command.dart +++ b/script/tool/lib/src/repo_package_info_check_command.dart @@ -16,7 +16,7 @@ const int _exitBadTableEntry = 3; const int _exitUnknownPackageEntry = 4; /// A command to verify repository-level metadata about packages, such as -/// repo README and CODEOWNERS entries. +/// repo README and auto-label entries. class RepoPackageInfoCheckCommand extends PackageLoopingCommand { /// Creates Dependabot check command instance. RepoPackageInfoCheckCommand(super.packagesDir, {super.gitDir}); @@ -27,9 +27,6 @@ class RepoPackageInfoCheckCommand extends PackageLoopingCommand { final Map> _readmeTableEntries = >{}; - /// Packages with entries in CODEOWNERS. - final List _ownedPackages = []; - /// Packages with entries in labeler.yml. final List _autoLabeledPackages = []; @@ -82,25 +79,6 @@ class RepoPackageInfoCheckCommand extends PackageLoopingCommand { } } - // Extract all of the CODEOWNERS package entries. - final packageOwnershipPattern = RegExp( - r'^((?:third_party/)?packages/(?:[^/]*/)?([^/]*))/\*\*', - ); - for (final String line - in _repoRoot.childFile('CODEOWNERS').readAsLinesSync()) { - final RegExpMatch? match = packageOwnershipPattern.firstMatch(line); - if (match == null) { - continue; - } - final String path = match.group(1)!; - final String name = match.group(2)!; - if (!_repoRoot.childDirectory(path).existsSync()) { - printError('Unknown directory "$path" in CODEOWNERS'); - throw ToolExit(_exitUnknownPackageEntry); - } - _ownedPackages.add(name); - } - // Extract all of the lebeler.yml package entries. // Validate the match rules rather than the label itself, as the labels // don't always correspond 1:1 to packages and package names. @@ -126,16 +104,6 @@ class RepoPackageInfoCheckCommand extends PackageLoopingCommand { final String packageName = package.directory.basename; final errors = []; - // All packages should have an owner. - // Platform interface packages are considered to be owned by the app-facing - // package owner. - if (!(_ownedPackages.contains(packageName) || - package.isPlatformInterface && - _ownedPackages.contains(package.directory.parent.basename))) { - printError('${indentation}Missing CODEOWNERS entry.'); - errors.add('Missing CODEOWNERS entry'); - } - // All packages should have an auto-applied label. For plugins, only the // group needs a rule, so check the app-facing package. if (!(package.isFederated && !package.isAppFacing) && diff --git a/script/tool/test/analyze_command_test.dart b/script/tool/test/analyze_command_test.dart index 0509f8d25988..ef2a609579ac 100644 --- a/script/tool/test/analyze_command_test.dart +++ b/script/tool/test/analyze_command_test.dart @@ -758,7 +758,7 @@ packages/package_a/$file MockProcess( stdout: ''' README.md -CODEOWNERS +SUGGESTED_REVIEWERS.md packages/package_a/CHANGELOG.md ''', ), @@ -1064,7 +1064,7 @@ packages/package_a/$file MockProcess( stdout: ''' README.md -CODEOWNERS +SUGGESTED_REVIEWERS.md packages/package_a/CHANGELOG.md packages/package_a/lib/foo.dart ''', @@ -1669,7 +1669,7 @@ packages/package_a/$file .gemini/config.yaml AGENTS.md README.md -CODEOWNERS +SUGGESTED_REVIEWERS.md packages/package_a/CHANGELOG.md packages/package_a/lib/foo.dart ''', diff --git a/script/tool/test/build_examples_command_test.dart b/script/tool/test/build_examples_command_test.dart index b2f66c5dbd6f..2b8a8c8952fd 100644 --- a/script/tool/test/build_examples_command_test.dart +++ b/script/tool/test/build_examples_command_test.dart @@ -1133,7 +1133,7 @@ packages/package_a/$file MockProcess( stdout: ''' README.md -CODEOWNERS +SUGGESTED_REVIEWERS.md packages/package_a/CHANGELOG.md ''', ), diff --git a/script/tool/test/common/file_filters_test.dart b/script/tool/test/common/file_filters_test.dart index 0143fb3dde30..dd06515509f2 100644 --- a/script/tool/test/common/file_filters_test.dart +++ b/script/tool/test/common/file_filters_test.dart @@ -9,10 +9,10 @@ void main() { group('isRepoLevelNonCodeImpactingFile', () { test('returns true for known non-code files', () { expect(isRepoLevelNonCodeImpactingFile('AUTHORS'), isTrue); - expect(isRepoLevelNonCodeImpactingFile('CODEOWNERS'), isTrue); expect(isRepoLevelNonCodeImpactingFile('CONTRIBUTING.md'), isTrue); expect(isRepoLevelNonCodeImpactingFile('LICENSE'), isTrue); expect(isRepoLevelNonCodeImpactingFile('README.md'), isTrue); + expect(isRepoLevelNonCodeImpactingFile('SUGGESTED_REVIEWERS.md'), isTrue); expect(isRepoLevelNonCodeImpactingFile('AGENTS.md'), isTrue); expect( isRepoLevelNonCodeImpactingFile('.github/PULL_REQUEST_TEMPLATE.md'), diff --git a/script/tool/test/dart_test_command_test.dart b/script/tool/test/dart_test_command_test.dart index 1a16a3703b3f..a6cac49ac0e7 100644 --- a/script/tool/test/dart_test_command_test.dart +++ b/script/tool/test/dart_test_command_test.dart @@ -881,7 +881,7 @@ packages/package_a/$file MockProcess( stdout: ''' README.md -CODEOWNERS +SUGGESTED_REVIEWERS.md packages/package_a/CHANGELOG.md ''', ), diff --git a/script/tool/test/drive_examples_command_test.dart b/script/tool/test/drive_examples_command_test.dart index f4aebdb569ac..6d4e44ca748a 100644 --- a/script/tool/test/drive_examples_command_test.dart +++ b/script/tool/test/drive_examples_command_test.dart @@ -1801,7 +1801,7 @@ packages/package_a/$file MockProcess( stdout: ''' README.md -CODEOWNERS +SUGGESTED_REVIEWERS.md .gitignore packages/package_a/CHANGELOG.md ''', diff --git a/script/tool/test/firebase_test_lab_command_test.dart b/script/tool/test/firebase_test_lab_command_test.dart index e469e1f2c645..2fd731ef8ad2 100644 --- a/script/tool/test/firebase_test_lab_command_test.dart +++ b/script/tool/test/firebase_test_lab_command_test.dart @@ -1068,7 +1068,7 @@ packages/package_a/$file MockProcess( stdout: ''' README.md -CODEOWNERS +SUGGESTED_REVIEWERS.md packages/package_a/CHANGELOG.md ''', ), diff --git a/script/tool/test/native_test_command_test.dart b/script/tool/test/native_test_command_test.dart index 6c51ed7f2fd1..1a34ebf5acb5 100644 --- a/script/tool/test/native_test_command_test.dart +++ b/script/tool/test/native_test_command_test.dart @@ -492,7 +492,7 @@ packages/package_a/$file MockProcess( stdout: ''' README.md -CODEOWNERS +SUGGESTED_REVIEWERS.md packages/package_a/CHANGELOG.md ''', ), diff --git a/script/tool/test/repo_package_info_check_command_test.dart b/script/tool/test/repo_package_info_check_command_test.dart index 341e0b2892c2..820c45ca6ce0 100644 --- a/script/tool/test/repo_package_info_check_command_test.dart +++ b/script/tool/test/repo_package_info_check_command_test.dart @@ -44,22 +44,6 @@ void main() { '''; } - void writeCodeOwners(List ownedPackages) { - final List subpaths = ownedPackages - .map( - (RepositoryPackage p) => p.isFederated - ? [ - p.directory.parent.basename, - p.directory.basename, - ].join('/') - : p.directory.basename, - ) - .toList(); - root.childFile('CODEOWNERS').writeAsStringSync(''' -${subpaths.map((String subpath) => 'packages/$subpath/** @someone').join('\n')} -'''); - } - String readmeTableEntry(String packageName) { final String encodedTag = Uri.encodeComponent('p: $packageName'); return '| [$packageName](./packages/$packageName/) | ' @@ -100,7 +84,6 @@ ${readmeTableHeader()} ${readmeTableEntry('a_package')} '''); writeAutoLabelerYaml(packages); - writeCodeOwners(packages); final List output = await runCapturingPrint(runner, [ 'repo-package-info-check', @@ -130,7 +113,6 @@ ${readmeTableEntry(pluginName)} '''); writeAutoLabelerYaml([packages.first]); writeAutoLabelerYaml([packages.first]); - writeCodeOwners(packages); // 4 packages * 2 checks (git, gh) = 8 calls. // Default mocks in setUp cover 1 call each. We need 3 more each. @@ -162,7 +144,6 @@ ${readmeTableHeader()} ${readmeTableEntry('another_package')} '''); writeAutoLabelerYaml(packages); - writeCodeOwners(packages); Error? commandError; final List output = await runCapturingPrint( @@ -193,7 +174,6 @@ ${readmeTableHeader()} ${readmeTableEntry('another_package')} '''); writeAutoLabelerYaml(packages); - writeCodeOwners(packages); Error? commandError; final List output = await runCapturingPrint( @@ -237,7 +217,6 @@ ${readmeTableHeader()} $entry '''); writeAutoLabelerYaml(packages); - writeCodeOwners(packages); Error? commandError; final List output = await runCapturingPrint( @@ -282,7 +261,6 @@ ${readmeTableHeader()} $entry '''); writeAutoLabelerYaml(packages); - writeCodeOwners(packages); Error? commandError; final List output = await runCapturingPrint( @@ -329,7 +307,6 @@ ${readmeTableHeader()} $entry '''); writeAutoLabelerYaml(packages); - writeCodeOwners(packages); Error? commandError; final List output = await runCapturingPrint( @@ -376,7 +353,6 @@ ${readmeTableHeader()} $entry '''); writeAutoLabelerYaml(packages); - writeCodeOwners(packages); Error? commandError; final List output = await runCapturingPrint( @@ -423,7 +399,6 @@ ${readmeTableHeader()} $entry '''); writeAutoLabelerYaml(packages); - writeCodeOwners(packages); Error? commandError; final List output = await runCapturingPrint( @@ -470,7 +445,6 @@ ${readmeTableHeader()} $entry '''); writeAutoLabelerYaml(packages); - writeCodeOwners(packages); Error? commandError; final List output = await runCapturingPrint( @@ -496,53 +470,15 @@ $entry ); }); - test('fails for missing CODEOWNER', () async { - const packageName = 'a_package'; - final packages = [ - createFakePackage('a_package', packagesDir), - ]; - - root.childFile('README.md').writeAsStringSync(''' -${readmeTableHeader()} -${readmeTableEntry(packageName)} -'''); - writeAutoLabelerYaml(packages); - writeCodeOwners([]); - - Error? commandError; - final List output = await runCapturingPrint( - runner, - ['repo-package-info-check'], - errorHandler: (Error e) { - commandError = e; - }, - ); - - expect(commandError, isA()); - expect( - output, - containsAllInOrder([ - contains('Missing CODEOWNERS entry.'), - contains( - 'a_package:\n' - ' Missing CODEOWNERS entry', - ), - ]), - ); - }); - test('fails for missing auto-labeler entry', () async { const packageName = 'a_package'; - final packages = [ - createFakePackage('a_package', packagesDir), - ]; + createFakePackage('a_package', packagesDir); root.childFile('README.md').writeAsStringSync(''' ${readmeTableHeader()} ${readmeTableEntry(packageName)} '''); writeAutoLabelerYaml([]); - writeCodeOwners(packages); Error? commandError; final List output = await runCapturingPrint( @@ -578,7 +514,6 @@ ${readmeTableHeader()} ${readmeTableEntry('a_package')} '''); writeAutoLabelerYaml([package]); - writeCodeOwners([package]); package.ciConfigFile.writeAsStringSync(''' release: @@ -603,7 +538,6 @@ ${readmeTableHeader()} ${readmeTableEntry('a_package')} '''); writeAutoLabelerYaml([package]); - writeCodeOwners([package]); final List output = await runCapturingPrint(runner, [ 'repo-package-info-check', @@ -626,7 +560,6 @@ ${readmeTableHeader()} ${readmeTableEntry('a_package')} '''); writeAutoLabelerYaml([package]); - writeCodeOwners([package]); package.ciConfigFile.writeAsStringSync(''' something: true '''); @@ -660,7 +593,6 @@ ${readmeTableHeader()} ${readmeTableEntry('a_package')} '''); writeAutoLabelerYaml([package]); - writeCodeOwners([package]); package.ciConfigFile.writeAsStringSync(''' release: batch: 1 @@ -699,7 +631,6 @@ ${readmeTableHeader()} ${readmeTableEntry('a_package')} '''); writeAutoLabelerYaml([package]); - writeCodeOwners([package]); return package; } diff --git a/third_party/packages/cupertino_icons/CHANGELOG.md b/third_party/packages/cupertino_icons/CHANGELOG.md index 7773a24be5eb..f90a47f4876b 100644 --- a/third_party/packages/cupertino_icons/CHANGELOG.md +++ b/third_party/packages/cupertino_icons/CHANGELOG.md @@ -1,5 +1,6 @@ -## NEXT +## 1.0.9 +* Removes empty Dart file. * Updates minimum supported SDK version to Flutter 3.35/Dart 3.9. ## 1.0.8 diff --git a/third_party/packages/cupertino_icons/lib/cupertino_icons.dart b/third_party/packages/cupertino_icons/lib/cupertino_icons.dart deleted file mode 100644 index 4ddfa3457a84..000000000000 --- a/third_party/packages/cupertino_icons/lib/cupertino_icons.dart +++ /dev/null @@ -1,8 +0,0 @@ -// Copyright 2013 The Flutter Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// File to create a lib/ directory for a well-formed .packages file and to -// conform to pub analyzer. -// -// This is an asset package. No dart import needed. diff --git a/third_party/packages/cupertino_icons/pubspec.yaml b/third_party/packages/cupertino_icons/pubspec.yaml index fa704b9d473e..2981bda5b6a2 100644 --- a/third_party/packages/cupertino_icons/pubspec.yaml +++ b/third_party/packages/cupertino_icons/pubspec.yaml @@ -3,7 +3,7 @@ name: cupertino_icons description: Default icons asset for Cupertino widgets based on Apple styled icons repository: https://github.com/flutter/packages/tree/main/third_party/packages/cupertino_icons issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+cupertino_icons%22 -version: 1.0.8 +version: 1.0.9 environment: sdk: ^3.9.0 diff --git a/third_party/packages/mustache_template/CHANGELOG.md b/third_party/packages/mustache_template/CHANGELOG.md index 67f53c1a8fc9..634e9abae3cd 100644 --- a/third_party/packages/mustache_template/CHANGELOG.md +++ b/third_party/packages/mustache_template/CHANGELOG.md @@ -1,3 +1,7 @@ +## 2.0.4 + +* Fixes a broken README link to the Mustache manual. + ## 2.0.3 * Updates minimum supported SDK version to Flutter 3.35/Dart 3.9. diff --git a/third_party/packages/mustache_template/README.md b/third_party/packages/mustache_template/README.md index 7602c2755160..cf4dab61e4e6 100644 --- a/third_party/packages/mustache_template/README.md +++ b/third_party/packages/mustache_template/README.md @@ -2,7 +2,7 @@ A Dart library to parse and render [mustache templates](https://mustache.github.io/). -See the [mustache manual](http://mustache.github.com/mustache.5.html) for detailed usage information. +See the [mustache manual](https://mustache.github.io/mustache.5.html) for detailed usage information. This library passes all [mustache specification](https://github.com/mustache/spec/tree/master/specs) tests. diff --git a/third_party/packages/mustache_template/pubspec.yaml b/third_party/packages/mustache_template/pubspec.yaml index 264e0ee0c4d4..8a8bdeae8b94 100644 --- a/third_party/packages/mustache_template/pubspec.yaml +++ b/third_party/packages/mustache_template/pubspec.yaml @@ -2,7 +2,7 @@ name: mustache_template description: A templating library that implements the Mustache template specification repository: https://github.com/flutter/packages/tree/main/third_party/packages/mustache_template issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+mustache_template%22 -version: 2.0.3 +version: 2.0.4 environment: sdk: ^3.9.0