/** * @file tests/unit/test_network.cpp * @brief Test src/network.* */ // test includes #include "../tests_common.h" // local includes #include TEST(NetworkClassificationTest, DeducedNetworkListsPreserveAddressScopes) { EXPECT_EQ(net::from_address("127.0.0.1"), net::PC); EXPECT_EQ(net::from_address("192.168.1.2"), net::LAN); EXPECT_EQ(net::from_address("100.64.0.1"), net::LAN); EXPECT_EQ(net::from_address("169.254.1.2"), net::LAN); EXPECT_EQ(net::from_address("8.8.8.8"), net::WAN); EXPECT_EQ(net::from_address("::1"), net::PC); EXPECT_EQ(net::from_address("fc00::1"), net::LAN); EXPECT_EQ(net::from_address("fe80::1"), net::LAN); EXPECT_EQ(net::from_address("2001:4860:4860::8888"), net::WAN); } /** * @brief Loopback and documentation addresses retain their classification when mapped to IPv6. */ TEST(NetworkClassificationTest, ClassifiesMappedIpv4AddressesWithoutChangingSubsequentLookups) { for (const auto *address : {"127.0.0.1", "192.0.2.1", "198.51.100.2", "203.0.113.3"}) { const auto expected = net::from_address(address); EXPECT_EQ(net::from_address(std::string {"::ffff:"} + address), expected); EXPECT_EQ(net::from_address(address), expected); } } struct MdnsInstanceNameTest: BaseTest, testing::WithParamInterface> {}; TEST_P(MdnsInstanceNameTest, Run) { auto [input, expected] = GetParam(); ASSERT_EQ(net::mdns_instance_name(input), expected); } INSTANTIATE_TEST_SUITE_P( MdnsInstanceNameTests, MdnsInstanceNameTest, testing::Values( std::make_tuple("shortname-123", "shortname-123"), std::make_tuple("space 123", "space-123"), std::make_tuple("hostname.domain.test", "hostname"), std::make_tuple("&", "Sunshine"), std::make_tuple("", "Sunshine"), std::make_tuple("😁", "Sunshine"), std::make_tuple(std::string(128, 'a'), std::string(63, 'a')) ) ); /** * @brief Test fixture for bind_address tests with setup/teardown */ class BindAddressTest: public BaseTest { protected: std::string original_bind_address; void SetUp() override { BaseTest::SetUp(); // Save the original bind_address config original_bind_address = config::sunshine.bind_address; } void TearDown() override { // Restore the original bind_address config config::sunshine.bind_address = original_bind_address; BaseTest::TearDown(); } }; /** * @brief Test that get_bind_address returns wildcard when bind_address is not configured */ TEST_F(BindAddressTest, DefaultBehaviorIPv4) { // Clear bind_address to test the default behavior config::sunshine.bind_address = ""; const auto bind_addr = net::get_bind_address(net::af_e::IPV4); ASSERT_EQ(bind_addr, "0.0.0.0"); } /** * @brief Test that get_bind_address returns wildcard when bind_address is not configured (IPv6) */ TEST_F(BindAddressTest, DefaultBehaviorIPv6) { // Clear bind_address to test the default behavior config::sunshine.bind_address = ""; const auto bind_addr = net::get_bind_address(net::af_e::BOTH); ASSERT_EQ(bind_addr, "::"); } /** * @brief Test that an empty bind address preserves the configured address family. */ TEST_F(BindAddressTest, EmptyAddressPreservesConfiguredFamily) { config::sunshine.bind_address = ""; EXPECT_EQ(net::get_effective_address_family(net::af_e::IPV4), net::af_e::IPV4); EXPECT_EQ(net::get_effective_address_family(net::af_e::BOTH), net::af_e::BOTH); } /** * @brief Test that an explicit IPv4 bind address selects an IPv4 socket. */ TEST_F(BindAddressTest, IPv4AddressSelectsIPv4Family) { config::sunshine.bind_address = "192.0.2.101"; EXPECT_EQ(net::get_effective_address_family(net::af_e::IPV4), net::af_e::IPV4); EXPECT_EQ(net::get_effective_address_family(net::af_e::BOTH), net::af_e::IPV4); } /** * @brief Test that an explicit IPv6 bind address does not override the configured family. */ TEST_F(BindAddressTest, IPv6AddressPreservesConfiguredFamily) { config::sunshine.bind_address = "2001:db8::1"; EXPECT_EQ(net::get_effective_address_family(net::af_e::IPV4), net::af_e::IPV4); EXPECT_EQ(net::get_effective_address_family(net::af_e::BOTH), net::af_e::BOTH); } /** * @brief Test that invalid bind addresses preserve the configured family for downstream error reporting. */ TEST_F(BindAddressTest, InvalidAddressPreservesConfiguredFamily) { config::sunshine.bind_address = "not-an-address"; EXPECT_EQ(net::get_effective_address_family(net::af_e::IPV4), net::af_e::IPV4); EXPECT_EQ(net::get_effective_address_family(net::af_e::BOTH), net::af_e::BOTH); } /** * @brief Test that bind addresses are formatted for use as URL hosts. */ TEST_F(BindAddressTest, AddressFormatsAsUrlHost) { config::sunshine.bind_address = ""; EXPECT_EQ(net::get_bind_address_url_host(), "localhost"); config::sunshine.bind_address = "198.51.100.56"; EXPECT_EQ(net::get_bind_address_url_host(), "198.51.100.56"); config::sunshine.bind_address = "2001:db8::1"; EXPECT_EQ(net::get_bind_address_url_host(), "[2001:db8::1]"); config::sunshine.bind_address = "not-an-address"; EXPECT_EQ(net::get_bind_address_url_host(), "not-an-address"); } /** * @brief Test that get_bind_address returns configured IPv4 address */ TEST_F(BindAddressTest, ConfiguredIPv4Address) { // Set a specific IPv4 address config::sunshine.bind_address = "192.168.1.100"; const auto bind_addr = net::get_bind_address(net::af_e::IPV4); ASSERT_EQ(bind_addr, "192.168.1.100"); } /** * @brief Test that get_bind_address returns configured IPv6 address */ TEST_F(BindAddressTest, ConfiguredIPv6Address) { // Set a specific IPv6 address config::sunshine.bind_address = "::1"; const auto bind_addr = net::get_bind_address(net::af_e::BOTH); ASSERT_EQ(bind_addr, "::1"); } /** * @brief Test that get_bind_address returns configured address regardless of address family */ TEST_F(BindAddressTest, ConfiguredAddressOverridesFamily) { // Set a specific IPv6 address but request IPv4 family // The configured address should still be returned config::sunshine.bind_address = "2001:db8::1"; const auto bind_addr = net::get_bind_address(net::af_e::IPV4); ASSERT_EQ(bind_addr, "2001:db8::1"); } /** * @brief Test with loopback addresses */ TEST_F(BindAddressTest, LoopbackAddresses) { // Test IPv4 loopback config::sunshine.bind_address = "127.0.0.1"; const auto bind_addr_v4 = net::get_bind_address(net::af_e::IPV4); ASSERT_EQ(bind_addr_v4, "127.0.0.1"); // Test IPv6 loopback config::sunshine.bind_address = "::1"; const auto bind_addr_v6 = net::get_bind_address(net::af_e::BOTH); ASSERT_EQ(bind_addr_v6, "::1"); } /** * @brief Test with link-local addresses */ TEST_F(BindAddressTest, LinkLocalAddresses) { // Test IPv4 link-local config::sunshine.bind_address = "169.254.1.1"; const auto bind_addr_v4 = net::get_bind_address(net::af_e::IPV4); ASSERT_EQ(bind_addr_v4, "169.254.1.1"); // Test IPv6 link-local config::sunshine.bind_address = "fe80::1"; const auto bind_addr_v6 = net::get_bind_address(net::af_e::BOTH); ASSERT_EQ(bind_addr_v6, "fe80::1"); } /** * @brief Test that af_to_any_address_string still works correctly */ TEST_F(BindAddressTest, WildcardAddressFunction) { ASSERT_EQ(net::af_to_any_address_string(net::af_e::IPV4), "0.0.0.0"); ASSERT_EQ(net::af_to_any_address_string(net::af_e::BOTH), "::"); }