// Copyright 2019 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "discovery/dnssd/public/dns_sd_instance.h" #include #include "gmock/gmock.h" #include "gtest/gtest.h" namespace openscreen { namespace discovery { TEST(DnsSdInstanceTests, InstanceLength) { EXPECT_TRUE(IsInstanceValid("instance")); EXPECT_TRUE(IsInstanceValid("name")); EXPECT_TRUE(IsInstanceValid("")); EXPECT_TRUE(IsInstanceValid( "Something63CharsLongabcdefghijklmnopqrstuvwxyz1234567890ABCDEFG")); EXPECT_FALSE(IsInstanceValid( "Something64CharsLongabcdefghijklmnopqrstuvwxyz1234567890ABCDEFGH")); } TEST(DnsSdInstanceTests, InstanceCharacters) { EXPECT_TRUE(IsInstanceValid("IncludingSpecialCharacters.+ =*&<<+`~\\/")); EXPECT_TRUE(IsInstanceValid(".+ =*&<<+`~\\/ ")); EXPECT_FALSE(IsInstanceValid(std::string(1, uint8_t{0x7F}))); EXPECT_FALSE(IsInstanceValid(std::string("name with ") + std::string(1, uint8_t{0x7F}) + " in the middle")); for (uint8_t bad_char = 0x0; bad_char <= 0x1F; bad_char++) { EXPECT_FALSE(IsInstanceValid(std::string(1, bad_char))); EXPECT_FALSE(IsInstanceValid(std::string("name with ") + std::string(1, bad_char) + " in the middle")); } } TEST(DnsSdInstanceTests, InstanceUTF8) { std::vector char_sets[] = { {0x80}, {0xC0}, {0xC0, 0xFF}, {0xE0}, {0xE0, 0xFF}, {0xE0, 0x80, 0x00}, {0xF0}, {0xF0, 0x00}, {0xF0, 0x80, 0xFF}, {0xF0, 0x80, 0x80, 0x0A}, }; for (const auto& set : char_sets) { std::string test_string = "start"; for (uint8_t ch : set) { test_string.append(std::string(1, ch)); } EXPECT_FALSE(IsInstanceValid(test_string)); } } TEST(DnsSdInstanceTests, ServiceLength) { // Too short. EXPECT_TRUE(IsServiceValid("_a._udp")); EXPECT_FALSE(IsServiceValid("_._udp")); // Too long. EXPECT_TRUE(IsServiceValid("_abcdefghijklmno._udp")); EXPECT_FALSE(IsServiceValid("_abcdefghijklmnop._udp")); } TEST(DnsSdInstanceTests, ServiceNonProtocolNameFormatting) { EXPECT_TRUE(IsServiceValid("_abcd._udp")); // Unexprected protocol string, EXPECT_FALSE(IsServiceValid("_abcd._ssl")); EXPECT_FALSE(IsServiceValid("_abcd._tls")); EXPECT_FALSE(IsServiceValid("_abcd._ucp")); // Extra characters before EXPECT_FALSE(IsServiceValid(" _abcd._udp")); EXPECT_FALSE(IsServiceValid("a_abcd._udp")); EXPECT_FALSE(IsServiceValid("-_abcd._udp")); // Extra characters after. EXPECT_FALSE(IsServiceValid("a_abcd._udp ")); EXPECT_FALSE(IsServiceValid("a_abcd._udp-")); EXPECT_FALSE(IsServiceValid("a_abcd._udpp")); EXPECT_FALSE(IsServiceValid("a_abcd._tcp_udp")); } TEST(DnsSdInstanceTests, ServiceProtocolNameFormatting) { EXPECT_TRUE(IsServiceValid("_abcd._udp")); // Disallowed Characters EXPECT_FALSE(IsServiceValid("_ab`d._udp")); EXPECT_FALSE(IsServiceValid("_a\\cd._udp")); EXPECT_FALSE(IsServiceValid("_ab.d._udp")); // Contains no letters EXPECT_FALSE(IsServiceValid("_123._udp")); EXPECT_FALSE(IsServiceValid("_1-3._udp")); // Improperly placed hyphen. EXPECT_FALSE(IsServiceValid("_-abcd._udp")); EXPECT_FALSE(IsServiceValid("_abcd-._udp")); // Adjacent hyphens. EXPECT_FALSE(IsServiceValid("_abc--d._udp")); EXPECT_FALSE(IsServiceValid("_a--bcd._tcp")); EXPECT_FALSE(IsServiceValid("_0a1b--c02d._udp")); EXPECT_FALSE(IsServiceValid("_0a--1._udp")); EXPECT_FALSE(IsServiceValid("_a--b._udp")); // Multiple, non-adjacent hyphens. EXPECT_TRUE(IsServiceValid("_a-b-c._udp")); EXPECT_TRUE(IsServiceValid("_a-1-c._udp")); } TEST(DnsSdInstanceTests, DomainDotPositions) { EXPECT_TRUE(IsDomainValid("192.168.0.0")); EXPECT_TRUE(IsDomainValid("....")); EXPECT_TRUE(IsDomainValid( "Something63CharsLongabcdefghijklmnopqrstuvwxyz1234567890ABCDEFG." "Something63CharsLongabcdefghijklmnopqrstuvwxyz1234567890ABCDEFG")); EXPECT_FALSE(IsDomainValid( "Something64CharsLongabcdefghijklmnopqrstuvwxyz1234567890ABCDEFGH." "Something63CharsLongabcdefghijklmnopqrstuvwxyz1234567890ABCDEFG")); } TEST(DnsSdInstanceTests, DomainCharacters) { EXPECT_TRUE(IsDomainValid("IncludingSpecialCharacters.+ =*&<<+`~\\/")); EXPECT_TRUE(IsDomainValid(".+ =*&<<+`~\\/ ")); EXPECT_FALSE(IsDomainValid(std::string(1, uint8_t{0x7F}))); EXPECT_FALSE(IsDomainValid(std::string("name with ") + std::string(1, uint8_t{0x7F}) + " in the middle")); for (uint8_t bad_char = 0x0; bad_char <= 0x1F; bad_char++) { EXPECT_FALSE(IsDomainValid(std::string(1, bad_char))); EXPECT_FALSE(IsDomainValid(std::string("name with ") + std::string(1, bad_char) + " in the middle")); } } TEST(DnsSdInstanceTests, DomainUTF8) { std::vector char_sets[] = { {0x80}, {0xC0}, {0xC0, 0xFF}, {0xE0}, {0xE0, 0xFF}, {0xE0, 0x80, 0x00}, {0xF0}, {0xF0, 0x00}, {0xF0, 0x80, 0xFF}, {0xF0, 0x80, 0x80, 0x0A}, }; for (const auto& set : char_sets) { std::string test_string = "start"; for (uint8_t ch : set) { test_string.append(std::string(1, ch)); } EXPECT_FALSE(IsDomainValid(test_string)); } } TEST(DnsSdInstanceTests, SubtypeCharacters) { EXPECT_TRUE(IsSubtypeValid("IncludingSpecialCharacters+ =*&<<+`~\\/")); EXPECT_TRUE(IsSubtypeValid("+ =*&<<+`~\\/ ")); EXPECT_FALSE(IsSubtypeValid("foo.bar")); EXPECT_FALSE(IsSubtypeValid(std::string(1, uint8_t{0x7F}))); EXPECT_FALSE(IsSubtypeValid(std::string("name with ") + std::string(1, uint8_t{0x7F}) + " in the middle")); for (uint8_t bad_char = 0x0; bad_char <= 0x1F; bad_char++) { EXPECT_FALSE(IsSubtypeValid(std::string(1, bad_char))); EXPECT_FALSE(IsSubtypeValid(std::string("name with ") + std::string(1, bad_char) + " in the middle")); } } TEST(DnsSdInstanceTests, SubtypeUTF8) { // Sets of bytes which do not form valid UTF8 encoded chars. std::vector char_sets[] = { {0x80}, {0xC0}, {0xC0, 0xFF}, {0xE0}, {0xE0, 0xFF}, {0xE0, 0x80, 0x00}, {0xF0}, {0xF0, 0x00}, {0xF0, 0x80, 0xFF}, {0xF0, 0x80, 0x80, 0x0A}, }; for (const auto& set : char_sets) { std::string test_string = "start"; for (uint8_t ch : set) { test_string.append(std::string(1, ch)); } EXPECT_FALSE(IsSubtypeValid(test_string)); } } TEST(DnsSdInstanceTests, SubtypeLength) { std::string kCharsAlmostMaxLength = "123456989012345678901234567890123456789012345678901234567890123"; ASSERT_EQ(kCharsAlmostMaxLength.size(), size_t{63}); EXPECT_TRUE(IsSubtypeValid(kCharsAlmostMaxLength)); EXPECT_FALSE(IsSubtypeValid(kCharsAlmostMaxLength + "4")); } TEST(DnsSdInstanceTests, ComparisonTests) { DnsSdTxtRecord set_record; set_record.SetValue("foo", "bar"); DnsSdInstance kIn1("instance", "_service._tcp", "local", {}, 80); DnsSdInstance kIn2("instance", "_service._tcp", "local", {}, 80); DnsSdInstance kIn3("instance2", "_service._tcp", "local", {}, 80); DnsSdInstance kIn4("instance", "_service2._tcp", "local", {}, 80); DnsSdInstance kIn5("instance", "_service._tcp", "local2", {}, 80); DnsSdInstance kIn6("instance", "_service._tcp", "local", set_record, 80); DnsSdInstance kIn7("instance", "_service._tcp", "local", {}, 79); DnsSdInstance kIn8("instance", "_service._tcp", "local", {}, 80, "foo"); DnsSdInstance kIn9("instance", "_service._tcp", "local", {}, 80, "foobar"); DnsSdInstance kIn10("instance", "_service._tcp", "local", {}, 80, "foo", "bar"); EXPECT_EQ(kIn1, kIn2); EXPECT_LT(kIn1, kIn3); EXPECT_LT(kIn1, kIn4); EXPECT_LT(kIn1, kIn5); EXPECT_LT(kIn1, kIn6); EXPECT_GT(kIn1, kIn7); EXPECT_LT(kIn1, kIn8); EXPECT_LT(kIn1, kIn9); EXPECT_LT(kIn1, kIn10); EXPECT_LT(kIn8, kIn9); EXPECT_LT(kIn8, kIn10); EXPECT_LT(kIn9, kIn10); } } // namespace discovery } // namespace openscreen