Skip to content

Fix exception for combined event on canceled sub#2345

Open
natebosch wants to merge 1 commit intomainfrom
combine-latest-error
Open

Fix exception for combined event on canceled sub#2345
natebosch wants to merge 1 commit intomainfrom
combine-latest-error

Conversation

@natebosch
Copy link
Member

@natebosch natebosch commented Mar 12, 2026

Fixes #2339

If a StreamSubscription.cancel occurs while the callback combining the
latest events is on going the inner subscriptions will also be canceled
and the variables assigned to null, so the non-null assertion which may
no longer hold. Switch the two ! to ? and add a test which fails
without the change.

If a `StreamSubscription.cancel` occurs while the callback combining the
latest events is on going the inner subscriptions will also be canceled
and the variables assigned to null, so the non-null assertion which may
no longer hold. Switch the two `!` to `?` and add a test which fails
without the change.
@github-actions
Copy link

Package publishing

Package Version Status Publish tag (post-merge)
package:bazel_worker 1.1.5 already published at pub.dev
package:benchmark_harness 2.4.0 already published at pub.dev
package:boolean_selector 2.1.2 already published at pub.dev
package:browser_launcher 1.2.0-wip WIP (no publish necessary)
package:cli_config 0.2.1-wip WIP (no publish necessary)
package:cli_util 0.5.0-wip WIP (no publish necessary)
package:clock 1.1.3-wip WIP (no publish necessary)
package:code_builder 4.11.1 already published at pub.dev
package:coverage 1.15.0 already published at pub.dev
package:csslib 1.0.2 already published at pub.dev
package:extension_discovery 2.1.0 already published at pub.dev
package:file 7.0.2-wip WIP (no publish necessary)
package:file_testing 3.1.0-wip WIP (no publish necessary)
package:glob 2.1.3 already published at pub.dev
package:graphs 2.4.0-wip WIP (no publish necessary)
package:html 0.15.7-wip WIP (no publish necessary)
package:io 1.1.0-wip WIP (no publish necessary)
package:json_rpc_2 4.1.0 already published at pub.dev
package:markdown 7.3.1 ready to publish markdown-v7.3.1
package:mime 2.1.0-wip WIP (no publish necessary)
package:oauth2 2.0.5 already published at pub.dev
package:package_config 2.3.0-wip WIP (no publish necessary)
package:pool 1.5.2 already published at pub.dev
package:process 5.0.5 (error) pubspec version (5.0.5) and changelog (5.0.6-wip) don't agree
package:pub_semver 2.2.0 already published at pub.dev
package:pubspec_parse 1.6.0-wip WIP (no publish necessary)
package:source_map_stack_trace 2.1.3-wip WIP (no publish necessary)
package:source_maps 0.10.14-wip WIP (no publish necessary)
package:source_span 1.10.2 already published at pub.dev
package:sse 4.2.0-wip (error) pubspec version (4.2.0-wip) and changelog (4.2.0) don't agree
package:stack_trace 1.12.2-wip (error) pubspec version (1.12.2-wip) and changelog (1.12.2-dev) don't agree
package:stream_channel 2.1.4 already published at pub.dev
package:stream_transform 2.1.2-wip WIP (no publish necessary)
package:string_scanner 1.4.2-wip WIP (no publish necessary)
package:term_glyph 1.2.3-wip WIP (no publish necessary)
package:test_reflective_loader 0.6.0 ready to publish test_reflective_loader-v0.6.0
package:timing 1.0.2 already published at pub.dev
package:unified_analytics 8.0.12 already published at pub.dev
package:watcher 1.2.2-wip WIP (no publish necessary)
package:yaml 3.1.3 already published at pub.dev
package:yaml_edit 2.2.4 already published at pub.dev

Documentation at https://github.com/dart-lang/ecosystem/wiki/Publishing-automation.

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request addresses a potential null pointer exception in combineLatest that could occur if a stream subscription is canceled while an asynchronous combine callback is in progress. The fix involves using null-aware operators (?) instead of non-null assertions (!) when resuming the inner subscriptions, which is the correct approach to handle the race condition where subscriptions could be nulled out by the cancellation handler. The PR includes a well-crafted test case that reproduces the issue and verifies the fix, along with an update to the changelog. The changes are sound and improve the robustness of the library.

@github-actions
Copy link

PR Health

Coverage ⚠️
File Coverage
pkgs/stream_transform/lib/src/combine_latest.dart 💔 Not covered

This check for test coverage is informational (issues shown here will not fail the PR).

This check can be disabled by tagging the PR with skip-coverage-check.

Breaking changes ✔️
Package Change Current Version New Version Needed Version Looking good?
stream_transform None 2.1.1 2.1.2-wip 2.1.2-wip ✔️

This check can be disabled by tagging the PR with skip-breaking-check.

Unused Dependencies ⚠️
Package Status
stream_transform
❗ Show Issues
These packages may be unused, or you may be using assets from these packages:
* async

For details on how to fix these, see dependency_validator.

This check can be disabled by tagging the PR with skip-unused-dependencies-check.

Changelog Entry ✔️
Package Changed Files

Changes to files need to be accounted for in their respective changelogs.

This check can be disabled by tagging the PR with skip-changelog-check.

License Headers ⚠️
""
Files
pkgs/stream_transform/lib/src/combine_latest.dart
pkgs/stream_transform/test/combine_latest_test.dart

All source files should start with a license header.

Unrelated files missing license headers
Files
pkgs/bazel_worker/benchmark/benchmark.dart
pkgs/bazel_worker/e2e_test/bin/async_worker.dart
pkgs/bazel_worker/e2e_test/bin/async_worker_in_isolate.dart
pkgs/bazel_worker/e2e_test/bin/sync_worker.dart
pkgs/bazel_worker/e2e_test/lib/async_worker.dart
pkgs/bazel_worker/e2e_test/lib/forwards_to_isolate_async_worker.dart
pkgs/bazel_worker/e2e_test/lib/sync_worker.dart
pkgs/bazel_worker/e2e_test/test/e2e_test.dart
pkgs/bazel_worker/example/client.dart
pkgs/bazel_worker/example/worker.dart
pkgs/bazel_worker/lib/bazel_worker.dart
pkgs/bazel_worker/lib/driver.dart
pkgs/bazel_worker/lib/src/async_message_grouper.dart
pkgs/bazel_worker/lib/src/constants.dart
pkgs/bazel_worker/lib/src/driver/driver.dart
pkgs/bazel_worker/lib/src/driver/driver_connection.dart
pkgs/bazel_worker/lib/src/message_grouper.dart
pkgs/bazel_worker/lib/src/message_grouper_state.dart
pkgs/bazel_worker/lib/src/sync_message_grouper.dart
pkgs/bazel_worker/lib/src/utils.dart
pkgs/bazel_worker/lib/src/worker/async_worker_loop.dart
pkgs/bazel_worker/lib/src/worker/sync_worker_loop.dart
pkgs/bazel_worker/lib/src/worker/worker_connection.dart
pkgs/bazel_worker/lib/src/worker/worker_loop.dart
pkgs/bazel_worker/lib/testing.dart
pkgs/bazel_worker/test/driver_connection_test.dart
pkgs/bazel_worker/test/driver_test.dart
pkgs/bazel_worker/test/message_grouper_test.dart
pkgs/bazel_worker/test/test_all.dart
pkgs/bazel_worker/test/worker_loop_test.dart
pkgs/benchmark_harness/bin/bench.dart
pkgs/benchmark_harness/example/template.dart
pkgs/benchmark_harness/integration_test/perf_benchmark_test.dart
pkgs/benchmark_harness/lib/benchmark_harness.dart
pkgs/benchmark_harness/lib/perf_benchmark_harness.dart
pkgs/benchmark_harness/lib/src/async_benchmark_base.dart
pkgs/benchmark_harness/lib/src/bench_command/bench_options.dart
pkgs/benchmark_harness/lib/src/bench_command/compile_and_run.dart
pkgs/benchmark_harness/lib/src/benchmark_base.dart
pkgs/benchmark_harness/lib/src/measurement.dart
pkgs/benchmark_harness/lib/src/perf_benchmark_base.dart
pkgs/benchmark_harness/lib/src/perf_benchmark_base_stub.dart
pkgs/benchmark_harness/lib/src/score_emitter.dart
pkgs/benchmark_harness/test/bench_command_test.dart
pkgs/benchmark_harness/test/benchmark_harness_test.dart
pkgs/benchmark_harness/test/result_emitter_test.dart
pkgs/boolean_selector/example/example.dart
pkgs/boolean_selector/lib/boolean_selector.dart
pkgs/boolean_selector/lib/src/all.dart
pkgs/boolean_selector/lib/src/ast.dart
pkgs/boolean_selector/lib/src/evaluator.dart
pkgs/boolean_selector/lib/src/impl.dart
pkgs/boolean_selector/lib/src/intersection_selector.dart
pkgs/boolean_selector/lib/src/none.dart
pkgs/boolean_selector/lib/src/parser.dart
pkgs/boolean_selector/lib/src/scanner.dart
pkgs/boolean_selector/lib/src/token.dart
pkgs/boolean_selector/lib/src/union_selector.dart
pkgs/boolean_selector/lib/src/validator.dart
pkgs/boolean_selector/lib/src/visitor.dart
pkgs/boolean_selector/test/equality_test.dart
pkgs/boolean_selector/test/evaluate_test.dart
pkgs/boolean_selector/test/parser_test.dart
pkgs/boolean_selector/test/scanner_test.dart
pkgs/boolean_selector/test/to_string_test.dart
pkgs/boolean_selector/test/validate_test.dart
pkgs/boolean_selector/test/variables_test.dart
pkgs/browser_launcher/example/main.dart
pkgs/browser_launcher/lib/browser_launcher.dart
pkgs/browser_launcher/lib/src/chrome.dart
pkgs/browser_launcher/test/chrome_test.dart
pkgs/cli_config/example/bin/cli_config_example.dart
pkgs/cli_config/lib/cli_config.dart
pkgs/cli_config/lib/src/cli_parser.dart
pkgs/cli_config/lib/src/cli_source.dart
pkgs/cli_config/lib/src/config.dart
pkgs/cli_config/lib/src/environment_parser.dart
pkgs/cli_config/lib/src/environment_source.dart
pkgs/cli_config/lib/src/file_parser.dart
pkgs/cli_config/lib/src/file_source.dart
pkgs/cli_config/lib/src/source.dart
pkgs/cli_config/test/cli_config_example_test.dart
pkgs/cli_config/test/cli_config_test.dart
pkgs/cli_config/test/cli_config_windows_test.dart
pkgs/cli_config/test/helpers.dart
pkgs/cli_util/example/main.dart
pkgs/cli_util/lib/cli_logging.dart
pkgs/cli_util/lib/cli_util.dart
pkgs/cli_util/lib/src/base_directories.dart
pkgs/cli_util/test/base_directories_test.dart
pkgs/cli_util/test/cli_util_test.dart
pkgs/clock/lib/clock.dart
pkgs/clock/lib/src/clock.dart
pkgs/clock/lib/src/default.dart
pkgs/clock/lib/src/stopwatch.dart
pkgs/clock/lib/src/utils.dart
pkgs/clock/test/clock_test.dart
pkgs/clock/test/default_test.dart
pkgs/clock/test/stopwatch_test.dart
pkgs/clock/test/utils.dart
pkgs/code_builder/example/example.dart
pkgs/code_builder/lib/code_builder.dart
pkgs/code_builder/lib/src/allocator.dart
pkgs/code_builder/lib/src/base.dart
pkgs/code_builder/lib/src/emitter.dart
pkgs/code_builder/lib/src/matchers.dart
pkgs/code_builder/lib/src/mixins/annotations.dart
pkgs/code_builder/lib/src/mixins/dartdoc.dart
pkgs/code_builder/lib/src/mixins/generics.dart
pkgs/code_builder/lib/src/specs/class.dart
pkgs/code_builder/lib/src/specs/code.dart
pkgs/code_builder/lib/src/specs/constructor.dart
pkgs/code_builder/lib/src/specs/directive.dart
pkgs/code_builder/lib/src/specs/enum.dart
pkgs/code_builder/lib/src/specs/expression.dart
pkgs/code_builder/lib/src/specs/expression/binary.dart
pkgs/code_builder/lib/src/specs/expression/closure.dart
pkgs/code_builder/lib/src/specs/expression/code.dart
pkgs/code_builder/lib/src/specs/expression/invoke.dart
pkgs/code_builder/lib/src/specs/expression/literal.dart
pkgs/code_builder/lib/src/specs/expression/parenthesized.dart
pkgs/code_builder/lib/src/specs/extension.dart
pkgs/code_builder/lib/src/specs/extension_type.dart
pkgs/code_builder/lib/src/specs/field.dart
pkgs/code_builder/lib/src/specs/library.dart
pkgs/code_builder/lib/src/specs/method.dart
pkgs/code_builder/lib/src/specs/mixin.dart
pkgs/code_builder/lib/src/specs/reference.dart
pkgs/code_builder/lib/src/specs/type_function.dart
pkgs/code_builder/lib/src/specs/type_record.dart
pkgs/code_builder/lib/src/specs/type_reference.dart
pkgs/code_builder/lib/src/specs/typedef.dart
pkgs/code_builder/lib/src/visitors.dart
pkgs/code_builder/test/allocator_test.dart
pkgs/code_builder/test/common.dart
pkgs/code_builder/test/const_test.dart
pkgs/code_builder/test/directive_test.dart
pkgs/code_builder/test/e2e/injection_test.dart
pkgs/code_builder/test/matcher_test.dart
pkgs/code_builder/test/specs/class_test.dart
pkgs/code_builder/test/specs/code/expression_test.dart
pkgs/code_builder/test/specs/code/statement_test.dart
pkgs/code_builder/test/specs/enum_test.dart
pkgs/code_builder/test/specs/extension_test.dart
pkgs/code_builder/test/specs/extension_type_test.dart
pkgs/code_builder/test/specs/field_test.dart
pkgs/code_builder/test/specs/library_test.dart
pkgs/code_builder/test/specs/method_test.dart
pkgs/code_builder/test/specs/mixin_test.dart
pkgs/code_builder/test/specs/record_type_test.dart
pkgs/code_builder/test/specs/type_reference_test.dart
pkgs/coverage/benchmark/many_isolates.dart
pkgs/coverage/bin/collect_coverage.dart
pkgs/coverage/bin/format_coverage.dart
pkgs/coverage/bin/run_and_collect.dart
pkgs/coverage/bin/test_with_coverage.dart
pkgs/coverage/lib/coverage.dart
pkgs/coverage/lib/src/chrome.dart
pkgs/coverage/lib/src/collect.dart
pkgs/coverage/lib/src/coverage_options.dart
pkgs/coverage/lib/src/coverage_percentage.dart
pkgs/coverage/lib/src/formatter.dart
pkgs/coverage/lib/src/hitmap.dart
pkgs/coverage/lib/src/isolate_paused_listener.dart
pkgs/coverage/lib/src/resolver.dart
pkgs/coverage/lib/src/run_and_collect.dart
pkgs/coverage/lib/src/util.dart
pkgs/coverage/test/chrome_test.dart
pkgs/coverage/test/collect_coverage_api_test.dart
pkgs/coverage/test/collect_coverage_config_test.dart
pkgs/coverage/test/collect_coverage_mock_test.dart
pkgs/coverage/test/collect_coverage_test.dart
pkgs/coverage/test/config_file_locator_test.dart
pkgs/coverage/test/coverage_percentage_test.dart
pkgs/coverage/test/filter_ignored_test.dart
pkgs/coverage/test/format_coverage_test.dart
pkgs/coverage/test/function_coverage_test.dart
pkgs/coverage/test/isolate_paused_listener_test.dart
pkgs/coverage/test/lcov_test.dart
pkgs/coverage/test/resolver_test.dart
pkgs/coverage/test/run_and_collect_test.dart
pkgs/coverage/test/test_files/function_coverage_app.dart
pkgs/coverage/test/test_files/test_app.dart
pkgs/coverage/test/test_files/test_app_isolate.dart
pkgs/coverage/test/test_files/test_library.dart
pkgs/coverage/test/test_files/test_library_part.dart
pkgs/coverage/test/test_util.dart
pkgs/coverage/test/test_with_coverage_package/lib/validate_lib.dart
pkgs/coverage/test/test_with_coverage_package/test/evaluate_test.dart
pkgs/coverage/test/test_with_coverage_package/test/product_test.dart
pkgs/coverage/test/test_with_coverage_package/test/sum_test.dart
pkgs/coverage/test/test_with_coverage_test.dart
pkgs/coverage/test/util_test.dart
pkgs/csslib/example/main.dart
pkgs/csslib/lib/src/analyzer.dart
pkgs/csslib/lib/src/css_printer.dart
pkgs/csslib/lib/src/messages.dart
pkgs/csslib/lib/src/polyfill.dart
pkgs/csslib/lib/src/preprocessor_options.dart
pkgs/csslib/lib/src/property.dart
pkgs/csslib/lib/src/token.dart
pkgs/csslib/lib/src/token_kind.dart
pkgs/csslib/lib/src/tokenizer.dart
pkgs/csslib/lib/src/tree.dart
pkgs/csslib/lib/src/tree_base.dart
pkgs/csslib/lib/src/tree_printer.dart
pkgs/csslib/lib/src/validate.dart
pkgs/csslib/lib/visitor.dart
pkgs/csslib/test/big_1_test.dart
pkgs/csslib/test/color_test.dart
pkgs/csslib/test/debug_test.dart
pkgs/csslib/test/declaration_test.dart
pkgs/csslib/test/error_test.dart
pkgs/csslib/test/escape_codes_test.dart
pkgs/csslib/test/extend_test.dart
pkgs/csslib/test/keyframes_test.dart
pkgs/csslib/test/mixin_test.dart
pkgs/csslib/test/nested_test.dart
pkgs/csslib/test/repros_test.dart
pkgs/csslib/test/selector_test.dart
pkgs/csslib/test/testing.dart
pkgs/csslib/test/third_party_samples_test.dart
pkgs/csslib/test/var_test.dart
pkgs/csslib/test/visitor_test.dart
pkgs/extension_discovery/example/hello_world/lib/hello_world.dart
pkgs/extension_discovery/example/hello_world_app/bin/hello.dart
pkgs/extension_discovery/lib/extension_discovery.dart
pkgs/extension_discovery/lib/src/expect_json.dart
pkgs/extension_discovery/lib/src/io.dart
pkgs/extension_discovery/lib/src/package_config.dart
pkgs/extension_discovery/lib/src/registry.dart
pkgs/extension_discovery/lib/src/yaml_config_format.dart
pkgs/extension_discovery/test/find_extensions_test.dart
pkgs/extension_discovery/test/integration_test.dart
pkgs/extension_discovery/test/package_config_test.dart
pkgs/extension_discovery/test/test_descriptor.dart
pkgs/extension_discovery/test/yaml_config_format_test.dart
pkgs/file/example/main.dart
pkgs/file/lib/chroot.dart
pkgs/file/lib/file.dart
pkgs/file/lib/local.dart
pkgs/file/lib/memory.dart
pkgs/file/lib/src/backends/chroot.dart
pkgs/file/lib/src/backends/chroot/chroot_directory.dart
pkgs/file/lib/src/backends/chroot/chroot_file.dart
pkgs/file/lib/src/backends/chroot/chroot_file_system.dart
pkgs/file/lib/src/backends/chroot/chroot_file_system_entity.dart
pkgs/file/lib/src/backends/chroot/chroot_link.dart
pkgs/file/lib/src/backends/chroot/chroot_random_access_file.dart
pkgs/file/lib/src/backends/local.dart
pkgs/file/lib/src/backends/local/local_directory.dart
pkgs/file/lib/src/backends/local/local_file.dart
pkgs/file/lib/src/backends/local/local_file_system.dart
pkgs/file/lib/src/backends/local/local_file_system_entity.dart
pkgs/file/lib/src/backends/local/local_link.dart
pkgs/file/lib/src/backends/memory.dart
pkgs/file/lib/src/backends/memory/clock.dart
pkgs/file/lib/src/backends/memory/common.dart
pkgs/file/lib/src/backends/memory/memory_directory.dart
pkgs/file/lib/src/backends/memory/memory_file.dart
pkgs/file/lib/src/backends/memory/memory_file_stat.dart
pkgs/file/lib/src/backends/memory/memory_file_system.dart
pkgs/file/lib/src/backends/memory/memory_file_system_entity.dart
pkgs/file/lib/src/backends/memory/memory_link.dart
pkgs/file/lib/src/backends/memory/memory_random_access_file.dart
pkgs/file/lib/src/backends/memory/node.dart
pkgs/file/lib/src/backends/memory/operations.dart
pkgs/file/lib/src/backends/memory/style.dart
pkgs/file/lib/src/backends/memory/utils.dart
pkgs/file/lib/src/common.dart
pkgs/file/lib/src/forwarding.dart
pkgs/file/lib/src/forwarding/forwarding_directory.dart
pkgs/file/lib/src/forwarding/forwarding_file.dart
pkgs/file/lib/src/forwarding/forwarding_file_system.dart
pkgs/file/lib/src/forwarding/forwarding_file_system_entity.dart
pkgs/file/lib/src/forwarding/forwarding_link.dart
pkgs/file/lib/src/forwarding/forwarding_random_access_file.dart
pkgs/file/lib/src/interface.dart
pkgs/file/lib/src/interface/directory.dart
pkgs/file/lib/src/interface/error_codes.dart
pkgs/file/lib/src/interface/error_codes_dart_io.dart
pkgs/file/lib/src/interface/error_codes_internal.dart
pkgs/file/lib/src/interface/file.dart
pkgs/file/lib/src/interface/file_system.dart
pkgs/file/lib/src/interface/file_system_entity.dart
pkgs/file/lib/src/interface/link.dart
pkgs/file/lib/src/io.dart
pkgs/file/test/chroot_test.dart
pkgs/file/test/common_tests.dart
pkgs/file/test/local_test.dart
pkgs/file/test/memory_operations_test.dart
pkgs/file/test/memory_test.dart
pkgs/file/test/utils.dart
pkgs/file/test/utils_test.dart
pkgs/file_testing/lib/file_testing.dart
pkgs/file_testing/lib/src/testing/core_matchers.dart
pkgs/file_testing/lib/src/testing/internal.dart
pkgs/glob/lib/glob.dart
pkgs/glob/lib/list_local_fs.dart
pkgs/glob/lib/src/ast.dart
pkgs/glob/lib/src/list_tree.dart
pkgs/glob/lib/src/parser.dart
pkgs/glob/lib/src/stream_pool.dart
pkgs/glob/lib/src/utils.dart
pkgs/glob/test/glob_test.dart
pkgs/glob/test/list_test.dart
pkgs/glob/test/match_test.dart
pkgs/glob/test/parse_test.dart
pkgs/graphs/benchmark/connected_components_benchmark.dart
pkgs/graphs/benchmark/shortest_path_benchmark.dart
pkgs/graphs/benchmark/shortest_path_worst_case_benchmark.dart
pkgs/graphs/example/crawl_async_example.dart
pkgs/graphs/example/example.dart
pkgs/graphs/lib/graphs.dart
pkgs/graphs/lib/src/crawl_async.dart
pkgs/graphs/lib/src/cycle_exception.dart
pkgs/graphs/lib/src/shortest_path.dart
pkgs/graphs/lib/src/strongly_connected_components.dart
pkgs/graphs/lib/src/topological_sort.dart
pkgs/graphs/lib/src/transitive_closure.dart
pkgs/graphs/test/crawl_async_test.dart
pkgs/graphs/test/shortest_path_test.dart
pkgs/graphs/test/strongly_connected_components_test.dart
pkgs/graphs/test/topological_sort_test.dart
pkgs/graphs/test/transitive_closure_test.dart
pkgs/graphs/test/utils/graph.dart
pkgs/graphs/test/utils/utils.dart
pkgs/html/example/main.dart
pkgs/html/lib/dom.dart
pkgs/html/lib/dom_parsing.dart
pkgs/html/lib/html_escape.dart
pkgs/html/lib/parser.dart
pkgs/html/lib/src/constants.dart
pkgs/html/lib/src/css_class_set.dart
pkgs/html/lib/src/encoding_parser.dart
pkgs/html/lib/src/html_input_stream.dart
pkgs/html/lib/src/list_proxy.dart
pkgs/html/lib/src/query_selector.dart
pkgs/html/lib/src/token.dart
pkgs/html/lib/src/tokenizer.dart
pkgs/html/lib/src/treebuilder.dart
pkgs/html/lib/src/utils.dart
pkgs/html/test/dom_test.dart
pkgs/html/test/parser_feature_test.dart
pkgs/html/test/parser_test.dart
pkgs/html/test/query_selector_test.dart
pkgs/html/test/selectors/level1_baseline_test.dart
pkgs/html/test/selectors/level1_lib.dart
pkgs/html/test/support.dart
pkgs/html/test/tokenizer_test.dart
pkgs/html/test/trie_test.dart
pkgs/html/tool/generate_trie.dart
pkgs/io/example/example.dart
pkgs/io/example/spawn_process_example.dart
pkgs/io/lib/ansi.dart
pkgs/io/lib/io.dart
pkgs/io/lib/src/ansi_code.dart
pkgs/io/lib/src/copy_path.dart
pkgs/io/lib/src/exit_code.dart
pkgs/io/lib/src/permissions.dart
pkgs/io/lib/src/process_manager.dart
pkgs/io/lib/src/shared_stdin.dart
pkgs/io/test/_files/stderr_hello.dart
pkgs/io/test/_files/stdin_echo.dart
pkgs/io/test/_files/stdout_hello.dart
pkgs/io/test/ansi_code_test.dart
pkgs/io/test/copy_path_test.dart
pkgs/io/test/permissions_test.dart
pkgs/io/test/process_manager_test.dart
pkgs/io/test/shared_stdin_test.dart
pkgs/json_rpc_2/example/client.dart
pkgs/json_rpc_2/example/main.dart
pkgs/json_rpc_2/lib/error_code.dart
pkgs/json_rpc_2/lib/json_rpc_2.dart
pkgs/json_rpc_2/lib/src/client.dart
pkgs/json_rpc_2/lib/src/exception.dart
pkgs/json_rpc_2/lib/src/parameters.dart
pkgs/json_rpc_2/lib/src/peer.dart
pkgs/json_rpc_2/lib/src/server.dart
pkgs/json_rpc_2/lib/src/utils.dart
pkgs/json_rpc_2/test/client/client_test.dart
pkgs/json_rpc_2/test/client/stream_test.dart
pkgs/json_rpc_2/test/client/utils.dart
pkgs/json_rpc_2/test/peer_test.dart
pkgs/json_rpc_2/test/server/batch_test.dart
pkgs/json_rpc_2/test/server/invalid_request_test.dart
pkgs/json_rpc_2/test/server/parameters_test.dart
pkgs/json_rpc_2/test/server/server_test.dart
pkgs/json_rpc_2/test/server/stream_test.dart
pkgs/json_rpc_2/test/server/utils.dart
pkgs/mime/example/example.dart
pkgs/mime/lib/mime.dart
pkgs/mime/lib/src/bound_multipart_stream.dart
pkgs/mime/lib/src/char_code.dart
pkgs/mime/lib/src/default_extension_map.dart
pkgs/mime/lib/src/extension.dart
pkgs/mime/lib/src/magic_number.dart
pkgs/mime/lib/src/mime_shared.dart
pkgs/mime/lib/src/mime_type.dart
pkgs/mime/lib/src/multipart_transformer.dart
pkgs/mime/test/default_extension_map_test.dart
pkgs/mime/test/extension_test.dart
pkgs/mime/test/mime_multipart_transformer_test.dart
pkgs/mime/test/mime_type_test.dart
pkgs/mime/tool/download_mime_info.dart
pkgs/mime/tool/regenerate_tables.dart
pkgs/oauth2/example/main.dart
pkgs/oauth2/lib/oauth2.dart
pkgs/oauth2/lib/src/authorization_code_grant.dart
pkgs/oauth2/lib/src/authorization_exception.dart
pkgs/oauth2/lib/src/client.dart
pkgs/oauth2/lib/src/client_credentials_grant.dart
pkgs/oauth2/lib/src/credentials.dart
pkgs/oauth2/lib/src/expiration_exception.dart
pkgs/oauth2/lib/src/handle_access_token_response.dart
pkgs/oauth2/lib/src/parameters.dart
pkgs/oauth2/lib/src/resource_owner_password_grant.dart
pkgs/oauth2/lib/src/utils.dart
pkgs/oauth2/test/authorization_code_grant_test.dart
pkgs/oauth2/test/client_credentials_grant_test.dart
pkgs/oauth2/test/client_test.dart
pkgs/oauth2/test/credentials_test.dart
pkgs/oauth2/test/handle_access_token_response_test.dart
pkgs/oauth2/test/resource_owner_password_grant_test.dart
pkgs/oauth2/test/utils.dart
pkgs/package_config/example/bin/package_config_of.dart
pkgs/package_config/lib/package_config.dart
pkgs/package_config/lib/package_config_types.dart
pkgs/package_config/lib/src/constants.dart
pkgs/package_config/lib/src/discovery.dart
pkgs/package_config/lib/src/errors.dart
pkgs/package_config/lib/src/package_config.dart
pkgs/package_config/lib/src/package_config_io.dart
pkgs/package_config/lib/src/util.dart
pkgs/package_config/lib/src/util_io.dart
pkgs/package_config/test/bench.dart
pkgs/package_config/test/discovery_test.dart
pkgs/package_config/test/discovery_uri_test.dart
pkgs/package_config/test/package_config_impl_test.dart
pkgs/package_config/test/src/util_io.dart
pkgs/pool/benchmark/for_each_benchmark.dart
pkgs/pool/lib/pool.dart
pkgs/pool/test/pool_test.dart
pkgs/process/example/main.dart
pkgs/process/lib/process.dart
pkgs/process/lib/src/interface/common.dart
pkgs/process/lib/src/interface/exceptions.dart
pkgs/process/lib/src/interface/local_process_manager.dart
pkgs/process/lib/src/interface/process_manager.dart
pkgs/process/lib/src/interface/process_wrapper.dart
pkgs/process/test/src/interface/common_test.dart
pkgs/process/test/src/interface/process_wrapper_test.dart
pkgs/process/test/utils.dart
pkgs/pub_semver/example/example.dart
pkgs/pub_semver/lib/pub_semver.dart
pkgs/pub_semver/lib/src/patterns.dart
pkgs/pub_semver/lib/src/utils.dart
pkgs/pub_semver/lib/src/version.dart
pkgs/pub_semver/lib/src/version_constraint.dart
pkgs/pub_semver/lib/src/version_range.dart
pkgs/pub_semver/lib/src/version_union.dart
pkgs/pub_semver/test/utils.dart
pkgs/pub_semver/test/version_constraint_test.dart
pkgs/pub_semver/test/version_range_test.dart
pkgs/pub_semver/test/version_test.dart
pkgs/pub_semver/test/version_union_test.dart
pkgs/pubspec_parse/lib/pubspec_parse.dart
pkgs/pubspec_parse/lib/src/dependency.dart
pkgs/pubspec_parse/lib/src/pubspec.dart
pkgs/pubspec_parse/lib/src/screenshot.dart
pkgs/pubspec_parse/test/dependency_test.dart
pkgs/pubspec_parse/test/ensure_build_test.dart
pkgs/pubspec_parse/test/git_uri_test.dart
pkgs/pubspec_parse/test/pub_utils.dart
pkgs/pubspec_parse/test/test_utils.dart
pkgs/pubspec_parse/test/tojson_test.dart
pkgs/source_map_stack_trace/lib/source_map_stack_trace.dart
pkgs/source_map_stack_trace/test/source_map_stack_trace_test.dart
pkgs/source_maps/lib/builder.dart
pkgs/source_maps/lib/parser.dart
pkgs/source_maps/lib/refactor.dart
pkgs/source_maps/lib/source_maps.dart
pkgs/source_maps/lib/src/source_map_span.dart
pkgs/source_maps/lib/src/utils.dart
pkgs/source_maps/lib/src/vlq.dart
pkgs/source_maps/test/builder_test.dart
pkgs/source_maps/test/common.dart
pkgs/source_maps/test/continued_region_test.dart
pkgs/source_maps/test/end2end_test.dart
pkgs/source_maps/test/parser_test.dart
pkgs/source_maps/test/printer_test.dart
pkgs/source_maps/test/refactor_test.dart
pkgs/source_maps/test/utils_test.dart
pkgs/source_maps/test/vlq_test.dart
pkgs/source_span/example/main.dart
pkgs/source_span/lib/source_span.dart
pkgs/source_span/lib/src/charcode.dart
pkgs/source_span/lib/src/colors.dart
pkgs/source_span/lib/src/file.dart
pkgs/source_span/lib/src/highlighter.dart
pkgs/source_span/lib/src/location.dart
pkgs/source_span/lib/src/location_mixin.dart
pkgs/source_span/lib/src/span.dart
pkgs/source_span/lib/src/span_exception.dart
pkgs/source_span/lib/src/span_mixin.dart
pkgs/source_span/lib/src/span_with_context.dart
pkgs/source_span/lib/src/utils.dart
pkgs/source_span/test/file_benchmark.dart
pkgs/source_span/test/file_test.dart
pkgs/source_span/test/location_test.dart
pkgs/source_span/test/utils_test.dart
pkgs/sse/example/index.dart
pkgs/sse/example/server.dart
pkgs/sse/lib/client/sse_client.dart
pkgs/sse/lib/server/sse_handler.dart
pkgs/sse/lib/src/server/sse_handler.dart
pkgs/sse/lib/src/util/id.dart
pkgs/sse/test/sse_test.dart
pkgs/sse/test/sse_unit_test.dart
pkgs/sse/test/web/index.dart
pkgs/stack_trace/example/example.dart
pkgs/stack_trace/lib/src/chain.dart
pkgs/stack_trace/lib/src/frame.dart
pkgs/stack_trace/lib/src/lazy_chain.dart
pkgs/stack_trace/lib/src/lazy_trace.dart
pkgs/stack_trace/lib/src/stack_zone_specification.dart
pkgs/stack_trace/lib/src/trace.dart
pkgs/stack_trace/lib/src/unparsed_frame.dart
pkgs/stack_trace/lib/src/utils.dart
pkgs/stack_trace/lib/src/vm_trace.dart
pkgs/stack_trace/lib/stack_trace.dart
pkgs/stack_trace/test/chain/chain_test.dart
pkgs/stack_trace/test/chain/dart2js_test.dart
pkgs/stack_trace/test/chain/utils.dart
pkgs/stack_trace/test/chain/vm_test.dart
pkgs/stack_trace/test/frame_test.dart
pkgs/stack_trace/test/trace_test.dart
pkgs/stack_trace/test/utils.dart
pkgs/stack_trace/test/vm_test.dart
pkgs/stream_channel/example/example.dart
pkgs/stream_channel/lib/isolate_channel.dart
pkgs/stream_channel/lib/src/close_guarantee_channel.dart
pkgs/stream_channel/lib/src/delegating_stream_channel.dart
pkgs/stream_channel/lib/src/disconnector.dart
pkgs/stream_channel/lib/src/guarantee_channel.dart
pkgs/stream_channel/lib/src/isolate_channel.dart
pkgs/stream_channel/lib/src/json_document_transformer.dart
pkgs/stream_channel/lib/src/multi_channel.dart
pkgs/stream_channel/lib/src/stream_channel_completer.dart
pkgs/stream_channel/lib/src/stream_channel_controller.dart
pkgs/stream_channel/lib/src/stream_channel_transformer.dart
pkgs/stream_channel/lib/stream_channel.dart
pkgs/stream_channel/test/disconnector_test.dart
pkgs/stream_channel/test/isolate_channel_test.dart
pkgs/stream_channel/test/json_document_transformer_test.dart
pkgs/stream_channel/test/multi_channel_test.dart
pkgs/stream_channel/test/stream_channel_completer_test.dart
pkgs/stream_channel/test/stream_channel_controller_test.dart
pkgs/stream_channel/test/stream_channel_test.dart
pkgs/stream_channel/test/with_close_guarantee_test.dart
pkgs/stream_channel/test/with_guarantees_test.dart
pkgs/stream_transform/example/main.dart
pkgs/stream_transform/lib/src/aggregate_sample.dart
pkgs/stream_transform/lib/src/async_expand.dart
pkgs/stream_transform/lib/src/async_map.dart
pkgs/stream_transform/lib/src/common_callbacks.dart
pkgs/stream_transform/lib/src/concatenate.dart
pkgs/stream_transform/lib/src/from_handlers.dart
pkgs/stream_transform/lib/src/merge.dart
pkgs/stream_transform/lib/src/rate_limit.dart
pkgs/stream_transform/lib/src/scan.dart
pkgs/stream_transform/lib/src/switch.dart
pkgs/stream_transform/lib/src/take_until.dart
pkgs/stream_transform/lib/src/tap.dart
pkgs/stream_transform/lib/src/where.dart
pkgs/stream_transform/lib/stream_transform.dart
pkgs/stream_transform/test/async_expand_test.dart
pkgs/stream_transform/test/async_map_buffer_test.dart
pkgs/stream_transform/test/async_map_sample_test.dart
pkgs/stream_transform/test/async_where_test.dart
pkgs/stream_transform/test/audit_test.dart
pkgs/stream_transform/test/buffer_test.dart
pkgs/stream_transform/test/combine_latest_all_test.dart
pkgs/stream_transform/test/concurrent_async_map_test.dart
pkgs/stream_transform/test/debounce_test.dart
pkgs/stream_transform/test/followd_by_test.dart
pkgs/stream_transform/test/from_handlers_test.dart
pkgs/stream_transform/test/merge_test.dart
pkgs/stream_transform/test/sample_test.dart
pkgs/stream_transform/test/scan_test.dart
pkgs/stream_transform/test/start_with_test.dart
pkgs/stream_transform/test/switch_test.dart
pkgs/stream_transform/test/take_until_test.dart
pkgs/stream_transform/test/tap_test.dart
pkgs/stream_transform/test/throttle_test.dart
pkgs/stream_transform/test/utils.dart
pkgs/stream_transform/test/where_not_null_test.dart
pkgs/stream_transform/test/where_type_test.dart
pkgs/string_scanner/example/example.dart
pkgs/string_scanner/lib/src/charcode.dart
pkgs/string_scanner/lib/src/eager_span_scanner.dart
pkgs/string_scanner/lib/src/exception.dart
pkgs/string_scanner/lib/src/line_scanner.dart
pkgs/string_scanner/lib/src/relative_span_scanner.dart
pkgs/string_scanner/lib/src/span_scanner.dart
pkgs/string_scanner/lib/src/utils.dart
pkgs/string_scanner/lib/string_scanner.dart
pkgs/string_scanner/test/error_test.dart
pkgs/string_scanner/test/line_scanner_test.dart
pkgs/string_scanner/test/span_scanner_test.dart
pkgs/string_scanner/test/string_scanner_test.dart
pkgs/string_scanner/test/utils.dart
pkgs/term_glyph/lib/term_glyph.dart
pkgs/term_glyph/test/symbol_test.dart
pkgs/term_glyph/tool/generate.dart
pkgs/test_reflective_loader/lib/test_reflective_loader.dart
pkgs/test_reflective_loader/test/hierarchy_test.dart
pkgs/test_reflective_loader/test/hierarchy_test.data.dart
pkgs/test_reflective_loader/test/location_test.dart
pkgs/test_reflective_loader/test/test_reflective_loader_test.dart
pkgs/timing/lib/src/clock.dart
pkgs/timing/lib/src/timing.dart
pkgs/timing/lib/timing.dart
pkgs/timing/test/timing_test.dart
pkgs/unified_analytics/example/log_stats.dart
pkgs/unified_analytics/example/sample_rate.dart
pkgs/unified_analytics/example/serving_surveys.dart
pkgs/unified_analytics/example/unified_analytics_example.dart
pkgs/unified_analytics/lib/src/analytics.dart
pkgs/unified_analytics/lib/src/asserts.dart
pkgs/unified_analytics/lib/src/config_handler.dart
pkgs/unified_analytics/lib/src/constants.dart
pkgs/unified_analytics/lib/src/enums.dart
pkgs/unified_analytics/lib/src/event.dart
pkgs/unified_analytics/lib/src/ga_client.dart
pkgs/unified_analytics/lib/src/initializer.dart
pkgs/unified_analytics/lib/src/log_handler.dart
pkgs/unified_analytics/lib/src/survey_handler.dart
pkgs/unified_analytics/lib/src/user_property.dart
pkgs/unified_analytics/lib/src/utils.dart
pkgs/unified_analytics/lib/testing.dart
pkgs/unified_analytics/lib/unified_analytics.dart
pkgs/unified_analytics/test/asserts_test.dart
pkgs/unified_analytics/test/error_handler_test.dart
pkgs/unified_analytics/test/event_test.dart
pkgs/unified_analytics/test/events_with_fake_test.dart
pkgs/unified_analytics/test/legacy_analytics_test.dart
pkgs/unified_analytics/test/log_handler_test.dart
pkgs/unified_analytics/test/no_op_analytics_test.dart
pkgs/unified_analytics/test/suppression_test.dart
pkgs/unified_analytics/test/survey_handler_test.dart
pkgs/unified_analytics/test/unified_analytics_test.dart
pkgs/unified_analytics/test/workflow_test.dart
pkgs/watcher/example/watch.dart
pkgs/watcher/lib/src/async_queue.dart
pkgs/watcher/lib/src/custom_watcher_factory.dart
pkgs/watcher/lib/src/directory_watcher.dart
pkgs/watcher/lib/src/directory_watcher/linux/linux_directory_watcher.dart
pkgs/watcher/lib/src/directory_watcher/linux/native_watch.dart
pkgs/watcher/lib/src/directory_watcher/linux/watch_tree.dart
pkgs/watcher/lib/src/directory_watcher/linux/watch_tree_root.dart
pkgs/watcher/lib/src/directory_watcher/polling/directory_list.dart
pkgs/watcher/lib/src/directory_watcher/polling/polling_directory_watcher.dart
pkgs/watcher/lib/src/directory_watcher/recursive/directory_tree.dart
pkgs/watcher/lib/src/directory_watcher/recursive/event_tree.dart
pkgs/watcher/lib/src/directory_watcher/recursive/isolate_recursive_directory_watcher.dart
pkgs/watcher/lib/src/directory_watcher/recursive/recursive_directory_watcher.dart
pkgs/watcher/lib/src/directory_watcher/recursive/recursive_native_watch.dart
pkgs/watcher/lib/src/directory_watcher/recursive/watched_directory_tree.dart
pkgs/watcher/lib/src/event.dart
pkgs/watcher/lib/src/event_batching.dart
pkgs/watcher/lib/src/file_watcher.dart
pkgs/watcher/lib/src/file_watcher/native.dart
pkgs/watcher/lib/src/file_watcher/polling.dart
pkgs/watcher/lib/src/paths.dart
pkgs/watcher/lib/src/polling.dart
pkgs/watcher/lib/src/resubscribable.dart
pkgs/watcher/lib/src/testing.dart
pkgs/watcher/lib/src/watch_event.dart
pkgs/watcher/lib/watcher.dart
pkgs/watcher/test/custom_watcher_factory_test.dart
pkgs/watcher/test/directory_watcher/client_simulator.dart
pkgs/watcher/test/directory_watcher/end_to_end_test_runner.dart
pkgs/watcher/test/directory_watcher/end_to_end_tests.dart
pkgs/watcher/test/directory_watcher/file_changer.dart
pkgs/watcher/test/directory_watcher/file_tests.dart
pkgs/watcher/test/directory_watcher/link_tests.dart
pkgs/watcher/test/directory_watcher/linux_test.dart
pkgs/watcher/test/directory_watcher/macos_test.dart
pkgs/watcher/test/directory_watcher/polling/directory_list_test.dart
pkgs/watcher/test/directory_watcher/polling_test.dart
pkgs/watcher/test/directory_watcher/recursive/event_tree_test.dart
pkgs/watcher/test/directory_watcher/relative_directory_test.dart
pkgs/watcher/test/directory_watcher/windows_isolate_test.dart
pkgs/watcher/test/directory_watcher/windows_test.dart
pkgs/watcher/test/event_batching_test.dart
pkgs/watcher/test/file_watcher/file_tests.dart
pkgs/watcher/test/file_watcher/link_tests.dart
pkgs/watcher/test/file_watcher/native_test.dart
pkgs/watcher/test/file_watcher/polling_test.dart
pkgs/watcher/test/file_watcher/startup_race_tests.dart
pkgs/watcher/test/no_subscription/linux_test.dart
pkgs/watcher/test/no_subscription/macos_test.dart
pkgs/watcher/test/no_subscription/polling_test.dart
pkgs/watcher/test/no_subscription/shared.dart
pkgs/watcher/test/no_subscription/windows_test.dart
pkgs/watcher/test/paths_test.dart
pkgs/watcher/test/ready/linux_test.dart
pkgs/watcher/test/ready/macos_test.dart
pkgs/watcher/test/ready/polling_test.dart
pkgs/watcher/test/ready/shared.dart
pkgs/watcher/test/ready/windows_test.dart
pkgs/watcher/test/utils.dart
pkgs/yaml/benchmark/benchmark.dart
pkgs/yaml/example/example.dart
pkgs/yaml/lib/src/charcodes.dart
pkgs/yaml/lib/src/equality.dart
pkgs/yaml/lib/src/error_listener.dart
pkgs/yaml/lib/src/event.dart
pkgs/yaml/lib/src/loader.dart
pkgs/yaml/lib/src/null_span.dart
pkgs/yaml/lib/src/parser.dart
pkgs/yaml/lib/src/scanner.dart
pkgs/yaml/lib/src/style.dart
pkgs/yaml/lib/src/token.dart
pkgs/yaml/lib/src/utils.dart
pkgs/yaml/lib/src/yaml_document.dart
pkgs/yaml/lib/src/yaml_exception.dart
pkgs/yaml/lib/src/yaml_node.dart
pkgs/yaml/lib/src/yaml_node_wrapper.dart
pkgs/yaml/lib/yaml.dart
pkgs/yaml/test/span_test.dart
pkgs/yaml/test/utils.dart
pkgs/yaml/test/yaml_node_wrapper_test.dart
pkgs/yaml_edit/example/example.dart
pkgs/yaml_edit/example/json2yaml.dart
pkgs/yaml_edit/lib/src/editor.dart
pkgs/yaml_edit/lib/src/equality.dart
pkgs/yaml_edit/lib/src/errors.dart
pkgs/yaml_edit/lib/src/list_mutations.dart
pkgs/yaml_edit/lib/src/map_mutations.dart
pkgs/yaml_edit/lib/src/source_edit.dart
pkgs/yaml_edit/lib/src/strings.dart
pkgs/yaml_edit/lib/src/utils.dart
pkgs/yaml_edit/lib/src/wrap.dart
pkgs/yaml_edit/lib/yaml_edit.dart
pkgs/yaml_edit/test/alias_test.dart
pkgs/yaml_edit/test/append_test.dart
pkgs/yaml_edit/test/crash_test/crash_test.dart
pkgs/yaml_edit/test/editor_test.dart
pkgs/yaml_edit/test/golden_test.dart
pkgs/yaml_edit/test/insert_test.dart
pkgs/yaml_edit/test/naughty_test.dart
pkgs/yaml_edit/test/parse_test.dart
pkgs/yaml_edit/test/prepend_test.dart
pkgs/yaml_edit/test/preservation_test.dart
pkgs/yaml_edit/test/problem_strings.dart
pkgs/yaml_edit/test/random_test.dart
pkgs/yaml_edit/test/remove_test.dart
pkgs/yaml_edit/test/source_edit_test.dart
pkgs/yaml_edit/test/special_test.dart
pkgs/yaml_edit/test/splice_test.dart
pkgs/yaml_edit/test/string_test.dart
pkgs/yaml_edit/test/test_case.dart
pkgs/yaml_edit/test/test_utils.dart
pkgs/yaml_edit/test/update_test.dart
pkgs/yaml_edit/test/windows_test.dart
pkgs/yaml_edit/test/wrap_test.dart
tool/readme_update.dart

This check can be disabled by tagging the PR with skip-license-check.

API leaks ✔️

The following packages contain symbols visible in the public API, but not exported by the library. Export these symbols or remove them from your publicly visible API.

Package Leaked API symbol Leaking sources

This check can be disabled by tagging the PR with skip-leaking-check.

Copy link
Member

@lrhn lrhn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM with preference-based suggestions.

test('handles combined results after stream is canceled', () async {
final source = Stream.value(1);
final other = Stream.value(2);
late final Completer<void> combineDelay;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could just create the completer here? It's only set once.
(Unless zones are involved, but I don't think they are.)

Or make the variable nullable, so you could use it to check whether the delayedSum has been called yet.

.combineLatest(other, delayedSum)
.listen(expectAsync1((_) {}, count: 0));

await pumpEventQueue();
Copy link
Member

@lrhn lrhn Mar 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pumpEventQueue scares me. I know there is no possible way it can always work correctly, and if the solution to failing is to "increase the number of pumps", then it's a fragile design. So if the test works, it might be by accident - it assumes an ordering between unrelated events.
No other test in the file uses pumpEventQueue.

I see that there is nothing to synchronize on in the code that runs after the delayedSum
completes. It explicitly does nothing (adds to a cancelled stream, does nothing for null).

The first pump should be possibler to handle with a synchronization future, like you do combineDelay.

Consider (or ignore, the test is fine if you're not unreasonably paranoid about pumpEventQueue like me):

 var stream1 = StreamController<int>();
 var stream2 = StreamController<int>();

 final onDelayedSum = Completer<void>();
 final delayedSumContinue = Completer<void>();
 Future<int> delayedSum(int a, int b) async {
   onDelayedSum.complete(null);
   await delayedSumContinue.future;
   return a + b;
 }
 final combinedStream = stream1.stream.combineLatest(stream2.stream);
 expect(stream1.hasListener, false);
 expect(stream2.hasListener, false);
 final subscription = combinedStream.listen(expectAsync1((_) {}, count: 0));
 expect(stream1.hasListener, true);
 expect(stream2.hasListener, true);
 expect(stream1.isPaused, false);
 expect(stream2.isPaused, false);
 stream1.add(1);
 stream2.add(2);
 await onDelayedSum.future;
 expect(stream1.hasListener, true);
 expect(stream2.hasListener, true);
 expect(stream1.isPaused, true);
 expect(stream2.isPaused, true);
 await subscription.cancel();
 expect(stream1.hasListener, false);
 expect(stream2.hasListener, false);
 delayedSumContinue.complete(null);
 // Should not cause error.

 // Do we need to pump-and-wait here?
 // Any later error should be ascribed to the test no matter what.
 // Is it because the test would  considered complete before the error would happen?
 // (If so, it'll still be an errror, it'll just be an error-after-test-completed. The program
 // won't end before all code has run.)
 // If so:
 await pumpEventQueue();
 // Or my preference, since it doesn't arbitrarily do 20 schedule microtasks,
 // but actually waits for all microtasks. It does allow other non-microtask events
 // to run first, but this is a controlled environment,
 // we know there shouldn't be any (that we care about).
 await Future<void>.delayed(Duration.zero); // Skips all microtasks.

sourceSubscription!.resume();
otherSubscription!.resume();
sourceSubscription?.resume();
otherSubscription?.resume();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(Could we put it all into the .then?

    result.then((value) {
      controller.add(value);
      _resume();
    }, onError: (Object error, Stacktrace stack) {
      controller.addError(error, stack);
      _resume();
    });
  
  // ...
  // Helper, since it occurs at least three times now, if also used as `onResume`.
  void _resume() { 
    sourceSubscription?.resume();
    otherSubscription?.resume();
  }

Mainly because whenComplete can be more expensive than it looks, because of the way it has to propagete the prior result conditionally. And in any case, .then+.whenComplete is more work, and more closures, than just a .then.

Can probably use ?. instad of !. everywhere. I expect it to generate marginally smaller code to not have a throwing branch, even if it's just calling a common function, but I haven't checked. The ! is better documentation, though.)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

combineLatest: "Null check operator used on a null value" when combine returns delayed Future and stream was cancelled

2 participants