#include #include #include "esphome/components/socket/socket.h" #ifdef USE_HOST namespace esphome::socket::testing { // ========================================================================= // join_multicast_group — EINVAL on malformed input // ========================================================================= TEST(JoinMulticastGroup, MalformedIPv4YieldsEINVAL) { auto sock = esphome::socket::socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); ASSERT_NE(sock, nullptr); errno = 0; EXPECT_FALSE(join_multicast_group(sock.get(), "not-an-ip")); EXPECT_EQ(errno, EINVAL); } TEST(JoinMulticastGroup, MalformedIPv6YieldsEINVAL) { // ':' present but parse fails — EINVAL regardless of USE_NETWORK_IPV6 auto sock = esphome::socket::socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); ASSERT_NE(sock, nullptr); errno = 0; EXPECT_FALSE(join_multicast_group(sock.get(), "gg::not-ipv6")); EXPECT_EQ(errno, EINVAL); } // ========================================================================= // join_multicast_group — IPv4 IP_ADD_MEMBERSHIP // ========================================================================= TEST(JoinMulticastGroup, IPv4JoinSetsIfIndexToZero) { auto sock = esphome::socket::socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); ASSERT_NE(sock, nullptr); uint32_t if_index = 99; // A host with no multicast route (e.g. an isolated container) cannot join if (join_multicast_group(sock.get(), "239.0.60.53", &if_index)) { EXPECT_EQ(if_index, 0u); } else { EXPECT_EQ(if_index, 99u); } } TEST(JoinMulticastGroup, IPv4JoinNullIfIndexOut) { auto sock = esphome::socket::socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); ASSERT_NE(sock, nullptr); errno = 0; EXPECT_TRUE(join_multicast_group(sock.get(), "239.0.60.53", nullptr) || errno != 0); } // ========================================================================= // join_multicast_group — IPv6 and set_ipv6_multicast_if // ========================================================================= #if USE_NETWORK_IPV6 TEST(JoinMulticastGroup, IPv6JoinSucceedsOrNoInterface) { auto sock = esphome::socket::socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP); ASSERT_NE(sock, nullptr); uint32_t if_index = 0; bool ok = join_multicast_group(sock.get(), "ff12::cafe", &if_index); if (ok) { EXPECT_GT(if_index, 0u); } else { EXPECT_EQ(errno, EADDRNOTAVAIL); } } TEST(SetIPv6MulticastIf, ProbeWithZeroIndexSucceedsOrNoInterface) { auto sock = esphome::socket::socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP); ASSERT_NE(sock, nullptr); errno = 0; EXPECT_TRUE(set_ipv6_multicast_if(sock.get(), 0) || errno == EADDRNOTAVAIL); } TEST(SetIPv6MulticastIf, ExplicitIndexFromJoinSucceeds) { auto sock_join = esphome::socket::socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP); auto sock_send = esphome::socket::socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP); ASSERT_NE(sock_join, nullptr); ASSERT_NE(sock_send, nullptr); uint32_t if_index = 0; bool joined = join_multicast_group(sock_join.get(), "ff12::cafe", &if_index); if (joined && if_index != 0) { EXPECT_TRUE(set_ipv6_multicast_if(sock_send.get(), if_index)); } } #endif // USE_NETWORK_IPV6 } // namespace esphome::socket::testing #endif // USE_HOST