tests/gateway/test_bluebubbles.py::TestBlueBubblesConfigLoading::test_apply_env_overrides_bluebubbles tests/gateway/test_bluebubbles.py::TestBlueBubblesConfigLoading::test_home_channel_set_from_env tests/gateway/test_bluebubbles.py::TestBlueBubblesConfigLoading::test_not_connected_without_password tests/gateway/test_bluebubbles.py::TestBlueBubblesHelpers::test_check_requirements tests/gateway/test_bluebubbles.py::TestBlueBubblesHelpers::test_supports_message_editing_is_false tests/gateway/test_bluebubbles.py::TestBlueBubblesHelpers::test_truncate_message_omits_pagination_suffixes tests/gateway/test_bluebubbles.py::TestBlueBubblesHelpers::test_send_splits_paragraphs_into_multiple_bubbles tests/gateway/test_bluebubbles.py::TestBlueBubblesHelpers::test_format_message_strips_markdown tests/gateway/test_bluebubbles.py::TestBlueBubblesHelpers::test_format_message_preserves_underscores_in_identifiers tests/gateway/test_bluebubbles.py::TestBlueBubblesHelpers::test_strip_markdown_headers tests/gateway/test_bluebubbles.py::TestBlueBubblesHelpers::test_strip_markdown_links tests/gateway/test_bluebubbles.py::TestBlueBubblesHelpers::test_init_normalizes_webhook_path tests/gateway/test_bluebubbles.py::TestBlueBubblesHelpers::test_init_preserves_leading_slash tests/gateway/test_bluebubbles.py::TestBlueBubblesHelpers::test_server_url_normalized tests/gateway/test_bluebubbles.py::TestBlueBubblesHelpers::test_server_url_adds_scheme tests/gateway/test_bluebubbles.py::TestBlueBubblesHelpers::test_default_mention_patterns_match_hermes_variants tests/gateway/test_bluebubbles.py::TestBlueBubblesHelpers::test_custom_mention_patterns_override_defaults tests/gateway/test_bluebubbles.py::TestBlueBubblesHelpers::test_clean_mention_text_strips_leading_wake_word tests/gateway/test_bluebubbles.py::TestBlueBubblesMentionGating::test_group_message_without_mention_is_acknowledged_and_skipped tests/gateway/test_bluebubbles.py::TestBlueBubblesMentionGating::test_group_message_with_default_mention_is_dispatched_cleaned tests/gateway/test_bluebubbles.py::TestBlueBubblesMentionGating::test_dm_message_does_not_require_mention tests/gateway/test_bluebubbles.py::TestBlueBubblesWebhookParsing::test_webhook_prefers_chat_guid_over_message_guid tests/gateway/test_bluebubbles.py::TestBlueBubblesWebhookParsing::test_webhook_can_fall_back_to_sender_when_chat_fields_missing tests/gateway/test_bluebubbles.py::TestBlueBubblesWebhookParsing::test_webhook_extracts_chat_guid_from_chats_array_dm tests/gateway/test_bluebubbles.py::TestBlueBubblesWebhookParsing::test_webhook_extracts_chat_guid_from_chats_array_group tests/gateway/test_bluebubbles.py::TestBlueBubblesWebhookParsing::test_extract_payload_record_accepts_list_data tests/gateway/test_bluebubbles.py::TestBlueBubblesWebhookParsing::test_extract_payload_record_dict_data tests/gateway/test_bluebubbles.py::TestBlueBubblesWebhookParsing::test_extract_payload_record_fallback_to_message tests/gateway/test_bluebubbles.py::TestBlueBubblesGuidResolution::test_raw_guid_returned_as_is tests/gateway/test_bluebubbles.py::TestBlueBubblesGuidResolution::test_empty_target_returns_none tests/gateway/test_bluebubbles.py::TestBlueBubblesAttachmentDownload::test_download_image_uses_image_cache tests/gateway/test_bluebubbles.py::TestBlueBubblesAttachmentDownload::test_download_audio_uses_audio_cache tests/gateway/test_bluebubbles.py::TestBlueBubblesAttachmentDownload::test_download_document_uses_document_cache tests/gateway/test_bluebubbles.py::TestBlueBubblesAttachmentDownload::test_download_returns_none_without_client tests/gateway/test_bluebubbles.py::TestBlueBubblesWebhookUrl::test_default_host tests/gateway/test_bluebubbles.py::TestBlueBubblesWebhookUrl::test_local_hosts_normalized[0.0.0.0] tests/gateway/test_bluebubbles.py::TestBlueBubblesWebhookUrl::test_local_hosts_normalized[127.0.0.1] tests/gateway/test_bluebubbles.py::TestBlueBubblesWebhookUrl::test_local_hosts_normalized[localhost] tests/gateway/test_bluebubbles.py::TestBlueBubblesWebhookUrl::test_local_hosts_normalized[::] tests/gateway/test_bluebubbles.py::TestBlueBubblesWebhookUrl::test_custom_host_preserved tests/gateway/test_bluebubbles.py::TestBlueBubblesWebhookUrl::test_register_url_embeds_password tests/gateway/test_bluebubbles.py::TestBlueBubblesWebhookUrl::test_register_url_url_encodes_password tests/gateway/test_bluebubbles.py::TestBlueBubblesWebhookUrl::test_register_url_for_log_masks_password tests/gateway/test_bluebubbles.py::TestBlueBubblesWebhookUrl::test_register_url_omits_query_when_no_password tests/gateway/test_bluebubbles.py::TestBlueBubblesWebhookRegistration::test_find_registered_webhooks_returns_matches tests/gateway/test_bluebubbles.py::TestBlueBubblesWebhookRegistration::test_find_registered_webhooks_empty_when_none tests/gateway/test_bluebubbles.py::TestBlueBubblesWebhookRegistration::test_find_registered_webhooks_handles_api_error tests/gateway/test_bluebubbles.py::TestBlueBubblesWebhookRegistration::test_register_fresh tests/gateway/test_bluebubbles.py::TestBlueBubblesWebhookRegistration::test_register_accepts_201 tests/gateway/test_bluebubbles.py::TestBlueBubblesWebhookRegistration::test_register_reuses_existing tests/gateway/test_bluebubbles.py::TestBlueBubblesWebhookRegistration::test_register_returns_false_without_client tests/gateway/test_bluebubbles.py::TestBlueBubblesWebhookRegistration::test_register_returns_false_on_server_error tests/gateway/test_bluebubbles.py::TestBlueBubblesWebhookRegistration::test_unregister_removes_matching tests/gateway/test_bluebubbles.py::TestBlueBubblesWebhookRegistration::test_unregister_removes_all_duplicates tests/gateway/test_bluebubbles.py::TestBlueBubblesWebhookRegistration::test_unregister_returns_false_without_client tests/gateway/test_bluebubbles.py::TestBlueBubblesWebhookRegistration::test_unregister_handles_api_failure_gracefully