| // Copyright 2021 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "net/dns/nsswitch_reader.h" |
| |
| #include <string> |
| #include <utility> |
| #include <vector> |
| |
| #include "base/check.h" |
| #include "base/functional/bind.h" |
| #include "testing/gmock/include/gmock/gmock.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| |
| namespace net { |
| namespace { |
| |
| class TestFileReader { |
| public: |
| explicit TestFileReader(std::string text) : text_(std::move(text)) {} |
| TestFileReader(const TestFileReader&) = delete; |
| TestFileReader& operator=(const TestFileReader&) = delete; |
| |
| NsswitchReader::FileReadCall GetFileReadCall() { |
| return base::BindRepeating(&TestFileReader::ReadFile, |
| base::Unretained(this)); |
| } |
| |
| std::string ReadFile() { |
| CHECK(!already_read_); |
| |
| already_read_ = true; |
| return text_; |
| } |
| |
| private: |
| std::string text_; |
| bool already_read_ = false; |
| }; |
| |
| class NsswitchReaderTest : public testing::Test { |
| public: |
| NsswitchReaderTest() = default; |
| NsswitchReaderTest(const NsswitchReaderTest&) = delete; |
| NsswitchReaderTest& operator=(const NsswitchReaderTest&) = delete; |
| |
| protected: |
| NsswitchReader reader_; |
| }; |
| |
| // Attempt to load the actual nsswitch.conf for the test machine and run |
| // rationality checks for the result. |
| TEST_F(NsswitchReaderTest, ActualReadAndParseHosts) { |
| std::vector<NsswitchReader::ServiceSpecification> services = |
| reader_.ReadAndParseHosts(); |
| |
| // Assume nobody will ever run this on a machine with more than 1000 |
| // configured services. |
| EXPECT_THAT(services, testing::SizeIs(testing::Le(1000u))); |
| |
| // Assume no service will ever have more than 10 configured actions per |
| // service. |
| for (const NsswitchReader::ServiceSpecification& service : services) { |
| EXPECT_THAT(service.actions, testing::SizeIs(testing::Le(10u))); |
| } |
| } |
| |
| TEST_F(NsswitchReaderTest, FileReadErrorResultsInDefault) { |
| TestFileReader file_reader(""); |
| reader_.set_file_read_call_for_testing(file_reader.GetFileReadCall()); |
| |
| std::vector<NsswitchReader::ServiceSpecification> services = |
| reader_.ReadAndParseHosts(); |
| |
| // Expect "files dns". |
| EXPECT_THAT( |
| services, |
| testing::ElementsAre( |
| NsswitchReader::ServiceSpecification(NsswitchReader::Service::kFiles), |
| NsswitchReader::ServiceSpecification(NsswitchReader::Service::kDns))); |
| } |
| |
| TEST_F(NsswitchReaderTest, MissingHostsResultsInDefault) { |
| const std::string kFile = |
| "passwd: files ldap\nshadow: files\ngroup: files ldap\n"; |
| TestFileReader file_reader(kFile); |
| reader_.set_file_read_call_for_testing(file_reader.GetFileReadCall()); |
| |
| std::vector<NsswitchReader::ServiceSpecification> services = |
| reader_.ReadAndParseHosts(); |
| |
| // Expect "files dns". |
| EXPECT_THAT( |
| services, |
| testing::ElementsAre( |
| NsswitchReader::ServiceSpecification(NsswitchReader::Service::kFiles), |
| NsswitchReader::ServiceSpecification(NsswitchReader::Service::kDns))); |
| } |
| |
| TEST_F(NsswitchReaderTest, ParsesAllKnownServices) { |
| const std::string kFile = |
| "hosts: files dns mdns mdns4 mdns6 mdns_minimal mdns4_minimal " |
| "mdns6_minimal myhostname resolve nis"; |
| TestFileReader file_reader(kFile); |
| reader_.set_file_read_call_for_testing(file_reader.GetFileReadCall()); |
| |
| std::vector<NsswitchReader::ServiceSpecification> services = |
| reader_.ReadAndParseHosts(); |
| |
| EXPECT_THAT( |
| services, |
| testing::ElementsAre( |
| NsswitchReader::ServiceSpecification(NsswitchReader::Service::kFiles), |
| NsswitchReader::ServiceSpecification(NsswitchReader::Service::kDns), |
| NsswitchReader::ServiceSpecification(NsswitchReader::Service::kMdns), |
| NsswitchReader::ServiceSpecification(NsswitchReader::Service::kMdns4), |
| NsswitchReader::ServiceSpecification(NsswitchReader::Service::kMdns6), |
| NsswitchReader::ServiceSpecification( |
| NsswitchReader::Service::kMdnsMinimal), |
| NsswitchReader::ServiceSpecification( |
| NsswitchReader::Service::kMdns4Minimal), |
| NsswitchReader::ServiceSpecification( |
| NsswitchReader::Service::kMdns6Minimal), |
| NsswitchReader::ServiceSpecification( |
| NsswitchReader::Service::kMyHostname), |
| NsswitchReader::ServiceSpecification( |
| NsswitchReader::Service::kResolve), |
| NsswitchReader::ServiceSpecification(NsswitchReader::Service::kNis))); |
| } |
| |
| TEST_F(NsswitchReaderTest, ParsesRepeatedServices) { |
| const std::string kFile = "hosts: mdns4 mdns6 mdns6 myhostname"; |
| TestFileReader file_reader(kFile); |
| reader_.set_file_read_call_for_testing(file_reader.GetFileReadCall()); |
| |
| std::vector<NsswitchReader::ServiceSpecification> services = |
| reader_.ReadAndParseHosts(); |
| |
| EXPECT_THAT( |
| services, |
| testing::ElementsAre( |
| NsswitchReader::ServiceSpecification(NsswitchReader::Service::kMdns4), |
| NsswitchReader::ServiceSpecification(NsswitchReader::Service::kMdns6), |
| NsswitchReader::ServiceSpecification(NsswitchReader::Service::kMdns6), |
| NsswitchReader::ServiceSpecification( |
| NsswitchReader::Service::kMyHostname))); |
| } |
| |
| TEST_F(NsswitchReaderTest, ParsesAllKnownActions) { |
| const std::string kFile = |
| "hosts: files [UNAVAIL=RETURN] [UNAVAIL=CONTINUE] [UNAVAIL=MERGE]"; |
| TestFileReader file_reader(kFile); |
| reader_.set_file_read_call_for_testing(file_reader.GetFileReadCall()); |
| |
| std::vector<NsswitchReader::ServiceSpecification> services = |
| reader_.ReadAndParseHosts(); |
| |
| EXPECT_THAT(services, |
| testing::ElementsAre(NsswitchReader::ServiceSpecification( |
| NsswitchReader::Service::kFiles, |
| {{/*negated=*/false, NsswitchReader::Status::kUnavailable, |
| NsswitchReader::Action::kReturn}, |
| {/*negated=*/false, NsswitchReader::Status::kUnavailable, |
| NsswitchReader::Action::kContinue}, |
| {/*negated=*/false, NsswitchReader::Status::kUnavailable, |
| NsswitchReader::Action::kMerge}}))); |
| } |
| |
| TEST_F(NsswitchReaderTest, ParsesAllKnownStatuses) { |
| const std::string kFile = |
| "hosts: dns [SUCCESS=RETURN] [NOTFOUND=RETURN] [UNAVAIL=RETURN] " |
| "[TRYAGAIN=RETURN]"; |
| TestFileReader file_reader(kFile); |
| reader_.set_file_read_call_for_testing(file_reader.GetFileReadCall()); |
| |
| std::vector<NsswitchReader::ServiceSpecification> services = |
| reader_.ReadAndParseHosts(); |
| |
| EXPECT_THAT(services, |
| testing::ElementsAre(NsswitchReader::ServiceSpecification( |
| NsswitchReader::Service::kDns, |
| {{/*negated=*/false, NsswitchReader::Status::kSuccess, |
| NsswitchReader::Action::kReturn}, |
| {/*negated=*/false, NsswitchReader::Status::kNotFound, |
| NsswitchReader::Action::kReturn}, |
| {/*negated=*/false, NsswitchReader::Status::kUnavailable, |
| NsswitchReader::Action::kReturn}, |
| {/*negated=*/false, NsswitchReader::Status::kTryAgain, |
| NsswitchReader::Action::kReturn}}))); |
| } |
| |
| TEST_F(NsswitchReaderTest, ParsesRepeatedActions) { |
| const std::string kFile = |
| "hosts: nis [!SUCCESS=RETURN] [NOTFOUND=RETURN] [NOTFOUND=RETURN] " |
| "[!UNAVAIL=RETURN]"; |
| TestFileReader file_reader(kFile); |
| reader_.set_file_read_call_for_testing(file_reader.GetFileReadCall()); |
| |
| std::vector<NsswitchReader::ServiceSpecification> services = |
| reader_.ReadAndParseHosts(); |
| |
| EXPECT_THAT(services, |
| testing::ElementsAre(NsswitchReader::ServiceSpecification( |
| NsswitchReader::Service::kNis, |
| {{/*negated=*/true, NsswitchReader::Status::kSuccess, |
| NsswitchReader::Action::kReturn}, |
| {/*negated=*/false, NsswitchReader::Status::kNotFound, |
| NsswitchReader::Action::kReturn}, |
| {/*negated=*/false, NsswitchReader::Status::kNotFound, |
| NsswitchReader::Action::kReturn}, |
| {/*negated=*/true, NsswitchReader::Status::kUnavailable, |
| NsswitchReader::Action::kReturn}}))); |
| } |
| |
| TEST_F(NsswitchReaderTest, ParsesCombinedActionLists) { |
| const std::string kFile = |
| "hosts: dns [SUCCESS=RETURN !NOTFOUND=RETURN UNAVAIL=RETURN] files"; |
| TestFileReader file_reader(kFile); |
| reader_.set_file_read_call_for_testing(file_reader.GetFileReadCall()); |
| |
| std::vector<NsswitchReader::ServiceSpecification> services = |
| reader_.ReadAndParseHosts(); |
| |
| EXPECT_THAT(services, |
| testing::ElementsAre( |
| NsswitchReader::ServiceSpecification( |
| NsswitchReader::Service::kDns, |
| {{/*negated=*/false, NsswitchReader::Status::kSuccess, |
| NsswitchReader::Action::kReturn}, |
| {/*negated=*/true, NsswitchReader::Status::kNotFound, |
| NsswitchReader::Action::kReturn}, |
| {/*negated=*/false, NsswitchReader::Status::kUnavailable, |
| NsswitchReader::Action::kReturn}}), |
| NsswitchReader::ServiceSpecification( |
| NsswitchReader::Service::kFiles))); |
| } |
| |
| TEST_F(NsswitchReaderTest, HandlesAtypicalWhitespace) { |
| const std::string kFile = |
| " database: service \n\n hosts: files\tdns mdns4 \t mdns6 \t " |
| "\t\n\t\n"; |
| TestFileReader file_reader(kFile); |
| reader_.set_file_read_call_for_testing(file_reader.GetFileReadCall()); |
| |
| std::vector<NsswitchReader::ServiceSpecification> services = |
| reader_.ReadAndParseHosts(); |
| |
| EXPECT_THAT( |
| services, |
| testing::ElementsAre( |
| NsswitchReader::ServiceSpecification(NsswitchReader::Service::kFiles), |
| NsswitchReader::ServiceSpecification(NsswitchReader::Service::kDns), |
| NsswitchReader::ServiceSpecification(NsswitchReader::Service::kMdns4), |
| NsswitchReader::ServiceSpecification( |
| NsswitchReader::Service::kMdns6))); |
| } |
| |
| TEST_F(NsswitchReaderTest, HandlesAtypicalWhitespaceInActions) { |
| const std::string kFile = |
| "hosts: dns [ !UNAVAIL=MERGE \t NOTFOUND=RETURN\t][ UNAVAIL=CONTINUE]"; |
| TestFileReader file_reader(kFile); |
| reader_.set_file_read_call_for_testing(file_reader.GetFileReadCall()); |
| |
| std::vector<NsswitchReader::ServiceSpecification> services = |
| reader_.ReadAndParseHosts(); |
| |
| EXPECT_THAT(services, |
| testing::ElementsAre(NsswitchReader::ServiceSpecification( |
| NsswitchReader::Service::kDns, |
| {{/*negated=*/true, NsswitchReader::Status::kUnavailable, |
| NsswitchReader::Action::kMerge}, |
| {/*negated=*/false, NsswitchReader::Status::kNotFound, |
| NsswitchReader::Action::kReturn}, |
| {/*negated=*/false, NsswitchReader::Status::kUnavailable, |
| NsswitchReader::Action::kContinue}}))); |
| } |
| |
| TEST_F(NsswitchReaderTest, ParsesActionsWithoutService) { |
| const std::string kFile = "hosts: [SUCCESS=RETURN]"; |
| TestFileReader file_reader(kFile); |
| reader_.set_file_read_call_for_testing(file_reader.GetFileReadCall()); |
| |
| std::vector<NsswitchReader::ServiceSpecification> services = |
| reader_.ReadAndParseHosts(); |
| |
| EXPECT_THAT(services, |
| testing::ElementsAre(NsswitchReader::ServiceSpecification( |
| NsswitchReader::Service::kUnknown, |
| {{/*negated=*/false, NsswitchReader::Status::kSuccess, |
| NsswitchReader::Action::kReturn}}))); |
| } |
| |
| TEST_F(NsswitchReaderTest, ParsesNegatedActions) { |
| const std::string kFile = |
| "hosts: mdns_minimal [!UNAVAIL=RETURN] [NOTFOUND=CONTINUE] " |
| "[!TRYAGAIN=CONTINUE]"; |
| TestFileReader file_reader(kFile); |
| reader_.set_file_read_call_for_testing(file_reader.GetFileReadCall()); |
| |
| std::vector<NsswitchReader::ServiceSpecification> services = |
| reader_.ReadAndParseHosts(); |
| |
| EXPECT_THAT(services, |
| testing::ElementsAre(NsswitchReader::ServiceSpecification( |
| NsswitchReader::Service::kMdnsMinimal, |
| {{/*negated=*/true, NsswitchReader::Status::kUnavailable, |
| NsswitchReader::Action::kReturn}, |
| {/*negated=*/false, NsswitchReader::Status::kNotFound, |
| NsswitchReader::Action::kContinue}, |
| {/*negated=*/true, NsswitchReader::Status::kTryAgain, |
| NsswitchReader::Action::kContinue}}))); |
| } |
| |
| TEST_F(NsswitchReaderTest, ParsesUnrecognizedServiceAsUnknown) { |
| const std::string kFile = |
| "passwd: files\nhosts: files super_awesome_service myhostname"; |
| TestFileReader file_reader(kFile); |
| reader_.set_file_read_call_for_testing(file_reader.GetFileReadCall()); |
| |
| std::vector<NsswitchReader::ServiceSpecification> services = |
| reader_.ReadAndParseHosts(); |
| |
| EXPECT_THAT(services, |
| testing::ElementsAre(NsswitchReader::ServiceSpecification( |
| NsswitchReader::Service::kFiles), |
| NsswitchReader::ServiceSpecification( |
| NsswitchReader::Service::kUnknown), |
| NsswitchReader::ServiceSpecification( |
| NsswitchReader::Service::kMyHostname))); |
| } |
| |
| TEST_F(NsswitchReaderTest, ParsesUnrecognizedStatusAsUnknown) { |
| const std::string kFile = |
| "hosts: nis [HELLO=CONTINUE]\nshadow: service\ndatabase: cheese"; |
| TestFileReader file_reader(kFile); |
| reader_.set_file_read_call_for_testing(file_reader.GetFileReadCall()); |
| |
| std::vector<NsswitchReader::ServiceSpecification> services = |
| reader_.ReadAndParseHosts(); |
| |
| EXPECT_THAT(services, |
| testing::ElementsAre(NsswitchReader::ServiceSpecification( |
| NsswitchReader::Service::kNis, |
| {{/*negated=*/false, NsswitchReader::Status::kUnknown, |
| NsswitchReader::Action::kContinue}}))); |
| } |
| |
| TEST_F(NsswitchReaderTest, ParsesUnrecognizedActionAsUnknown) { |
| const std::string kFile = |
| "more: service\nhosts: mdns6 [!UNAVAIL=HI]\nshadow: service"; |
| TestFileReader file_reader(kFile); |
| reader_.set_file_read_call_for_testing(file_reader.GetFileReadCall()); |
| |
| std::vector<NsswitchReader::ServiceSpecification> services = |
| reader_.ReadAndParseHosts(); |
| |
| EXPECT_THAT(services, |
| testing::ElementsAre(NsswitchReader::ServiceSpecification( |
| NsswitchReader::Service::kMdns6, |
| {{/*negated=*/true, NsswitchReader::Status::kUnavailable, |
| NsswitchReader::Action::kUnknown}}))); |
| } |
| |
| TEST_F(NsswitchReaderTest, ParsesInvalidActionsAsUnknown) { |
| const std::string kFile = "hosts: mdns_minimal [a=b=c] nis"; |
| TestFileReader file_reader(kFile); |
| reader_.set_file_read_call_for_testing(file_reader.GetFileReadCall()); |
| |
| std::vector<NsswitchReader::ServiceSpecification> services = |
| reader_.ReadAndParseHosts(); |
| |
| EXPECT_THAT( |
| services, |
| testing::ElementsAre( |
| NsswitchReader::ServiceSpecification( |
| NsswitchReader::Service::kMdnsMinimal, |
| {{/*negated=*/false, NsswitchReader::Status::kUnknown, |
| NsswitchReader::Action::kUnknown}}), |
| NsswitchReader::ServiceSpecification(NsswitchReader::Service::kNis))); |
| } |
| |
| TEST_F(NsswitchReaderTest, IgnoresInvalidlyClosedActions) { |
| const std::string kFile = "hosts: myhostname [SUCCESS=MERGE"; |
| TestFileReader file_reader(kFile); |
| reader_.set_file_read_call_for_testing(file_reader.GetFileReadCall()); |
| |
| std::vector<NsswitchReader::ServiceSpecification> services = |
| reader_.ReadAndParseHosts(); |
| |
| EXPECT_THAT(services, |
| testing::ElementsAre(NsswitchReader::ServiceSpecification( |
| NsswitchReader::Service::kMyHostname, |
| {{/*negated=*/false, NsswitchReader::Status::kSuccess, |
| NsswitchReader::Action::kMerge}}))); |
| } |
| |
| TEST_F(NsswitchReaderTest, ParsesServicesAfterInvalidlyClosedActionsAsUnknown) { |
| const std::string kFile = "hosts: resolve [SUCCESS=CONTINUE dns"; |
| TestFileReader file_reader(kFile); |
| reader_.set_file_read_call_for_testing(file_reader.GetFileReadCall()); |
| |
| std::vector<NsswitchReader::ServiceSpecification> services = |
| reader_.ReadAndParseHosts(); |
| |
| EXPECT_THAT(services, |
| testing::ElementsAre(NsswitchReader::ServiceSpecification( |
| NsswitchReader::Service::kResolve, |
| {{/*negated=*/false, NsswitchReader::Status::kSuccess, |
| NsswitchReader::Action::kContinue}, |
| {/*negated=*/false, NsswitchReader::Status::kUnknown, |
| NsswitchReader::Action::kUnknown}}))); |
| } |
| |
| TEST_F(NsswitchReaderTest, IgnoresComments) { |
| const std::string kFile = |
| "#hosts: files super_awesome_service myhostname\nnetmask: service"; |
| TestFileReader file_reader(kFile); |
| reader_.set_file_read_call_for_testing(file_reader.GetFileReadCall()); |
| |
| std::vector<NsswitchReader::ServiceSpecification> services = |
| reader_.ReadAndParseHosts(); |
| |
| // Expect "files dns" due to not finding an uncommented "hosts:" row. |
| EXPECT_THAT( |
| services, |
| testing::ElementsAre( |
| NsswitchReader::ServiceSpecification(NsswitchReader::Service::kFiles), |
| NsswitchReader::ServiceSpecification(NsswitchReader::Service::kDns))); |
| } |
| |
| TEST_F(NsswitchReaderTest, IgnoresEndOfLineComments) { |
| const std::string kFile = |
| "hosts: files super_awesome_service myhostname # dns"; |
| TestFileReader file_reader(kFile); |
| reader_.set_file_read_call_for_testing(file_reader.GetFileReadCall()); |
| |
| std::vector<NsswitchReader::ServiceSpecification> services = |
| reader_.ReadAndParseHosts(); |
| |
| EXPECT_THAT(services, |
| testing::ElementsAre(NsswitchReader::ServiceSpecification( |
| NsswitchReader::Service::kFiles), |
| NsswitchReader::ServiceSpecification( |
| NsswitchReader::Service::kUnknown), |
| NsswitchReader::ServiceSpecification( |
| NsswitchReader::Service::kMyHostname))); |
| } |
| |
| TEST_F(NsswitchReaderTest, IgnoresCapitalization) { |
| const std::string kFile = "HoStS: mDNS6 [!uNaVaIl=MeRgE]"; |
| TestFileReader file_reader(kFile); |
| reader_.set_file_read_call_for_testing(file_reader.GetFileReadCall()); |
| |
| std::vector<NsswitchReader::ServiceSpecification> services = |
| reader_.ReadAndParseHosts(); |
| |
| EXPECT_THAT(services, |
| testing::ElementsAre(NsswitchReader::ServiceSpecification( |
| NsswitchReader::Service::kMdns6, |
| {{/*negated=*/true, NsswitchReader::Status::kUnavailable, |
| NsswitchReader::Action::kMerge}}))); |
| } |
| |
| TEST_F(NsswitchReaderTest, IgnoresEmptyActions) { |
| const std::string kFile = "hosts: mdns_minimal [ \t ][] [ ]"; |
| TestFileReader file_reader(kFile); |
| reader_.set_file_read_call_for_testing(file_reader.GetFileReadCall()); |
| |
| std::vector<NsswitchReader::ServiceSpecification> services = |
| reader_.ReadAndParseHosts(); |
| |
| EXPECT_THAT(services, |
| testing::ElementsAre(NsswitchReader::ServiceSpecification( |
| NsswitchReader::Service::kMdnsMinimal))); |
| } |
| |
| TEST_F(NsswitchReaderTest, IgnoresRepeatedActionBrackets) { |
| const std::string kFile = "hosts: mdns [[SUCCESS=RETURN]]]dns"; |
| TestFileReader file_reader(kFile); |
| reader_.set_file_read_call_for_testing(file_reader.GetFileReadCall()); |
| |
| std::vector<NsswitchReader::ServiceSpecification> services = |
| reader_.ReadAndParseHosts(); |
| |
| EXPECT_THAT( |
| services, |
| testing::ElementsAre( |
| NsswitchReader::ServiceSpecification( |
| NsswitchReader::Service::kMdns, |
| {{/*negated=*/false, NsswitchReader::Status::kSuccess, |
| NsswitchReader::Action::kReturn}}), |
| NsswitchReader::ServiceSpecification(NsswitchReader::Service::kDns))); |
| } |
| |
| TEST_F(NsswitchReaderTest, IgnoresRepeatedActionBracketsWithWhitespace) { |
| const std::string kFile = "hosts: mdns [ [ SUCCESS=RETURN ]\t] ]\t mdns6"; |
| TestFileReader file_reader(kFile); |
| reader_.set_file_read_call_for_testing(file_reader.GetFileReadCall()); |
| |
| std::vector<NsswitchReader::ServiceSpecification> services = |
| reader_.ReadAndParseHosts(); |
| |
| EXPECT_THAT(services, |
| testing::ElementsAre( |
| NsswitchReader::ServiceSpecification( |
| NsswitchReader::Service::kMdns, |
| {{/*negated=*/false, NsswitchReader::Status::kSuccess, |
| NsswitchReader::Action::kReturn}}), |
| NsswitchReader::ServiceSpecification( |
| NsswitchReader::Service::kMdns6))); |
| } |
| |
| TEST_F(NsswitchReaderTest, RejectsNonSensicalActionBrackets) { |
| const std::string kFile = "hosts: mdns4 [UNAVAIL[=MERGE]]"; |
| TestFileReader file_reader(kFile); |
| reader_.set_file_read_call_for_testing(file_reader.GetFileReadCall()); |
| |
| std::vector<NsswitchReader::ServiceSpecification> services = |
| reader_.ReadAndParseHosts(); |
| |
| EXPECT_THAT(services, |
| testing::ElementsAre(NsswitchReader::ServiceSpecification( |
| NsswitchReader::Service::kMdns4, |
| {{/*negated=*/false, NsswitchReader::Status::kUnknown, |
| NsswitchReader::Action::kMerge}}))); |
| } |
| |
| TEST_F(NsswitchReaderTest, RejectsServicesWithBrackets) { |
| const std::string kFile = "hosts: se]r[vice[name"; |
| TestFileReader file_reader(kFile); |
| reader_.set_file_read_call_for_testing(file_reader.GetFileReadCall()); |
| |
| std::vector<NsswitchReader::ServiceSpecification> services = |
| reader_.ReadAndParseHosts(); |
| |
| EXPECT_THAT(services, |
| testing::ElementsAre(NsswitchReader::ServiceSpecification( |
| NsswitchReader::Service::kUnknown))); |
| } |
| |
| // Other than the case of repeating opening brackets, nested brackets are not |
| // valid and should just get treated as part of an action label. |
| TEST_F(NsswitchReaderTest, RejectsNestedActionBrackets) { |
| const std::string kFile = |
| "hosts: nis [SUCCESS=RETURN [NOTFOUND=CONTINUE] UNAVAIL=MERGE]"; |
| TestFileReader file_reader(kFile); |
| reader_.set_file_read_call_for_testing(file_reader.GetFileReadCall()); |
| |
| std::vector<NsswitchReader::ServiceSpecification> services = |
| reader_.ReadAndParseHosts(); |
| |
| EXPECT_THAT(services, |
| testing::ElementsAre( |
| NsswitchReader::ServiceSpecification( |
| NsswitchReader::Service::kNis, |
| {{/*negated=*/false, NsswitchReader::Status::kSuccess, |
| NsswitchReader::Action::kReturn}, |
| {/*negated=*/false, NsswitchReader::Status::kUnknown, |
| NsswitchReader::Action::kContinue}}), |
| NsswitchReader::ServiceSpecification( |
| NsswitchReader::Service::kUnknown))); |
| } |
| |
| TEST_F(NsswitchReaderTest, IgnoresEmptyActionWithRepeatedBrackets) { |
| const std::string kFile = "hosts: files [[[]]]] mdns"; |
| TestFileReader file_reader(kFile); |
| reader_.set_file_read_call_for_testing(file_reader.GetFileReadCall()); |
| |
| std::vector<NsswitchReader::ServiceSpecification> services = |
| reader_.ReadAndParseHosts(); |
| |
| EXPECT_THAT(services, |
| testing::ElementsAre(NsswitchReader::ServiceSpecification( |
| NsswitchReader::Service::kFiles), |
| NsswitchReader::ServiceSpecification( |
| NsswitchReader::Service::kMdns))); |
| } |
| |
| TEST_F(NsswitchReaderTest, IgnoresEmptyActionAtEndOfString) { |
| const std::string kFile = "hosts: dns [["; |
| TestFileReader file_reader(kFile); |
| reader_.set_file_read_call_for_testing(file_reader.GetFileReadCall()); |
| |
| std::vector<NsswitchReader::ServiceSpecification> services = |
| reader_.ReadAndParseHosts(); |
| |
| EXPECT_THAT(services, |
| testing::ElementsAre(NsswitchReader::ServiceSpecification( |
| NsswitchReader::Service::kDns))); |
| } |
| |
| } // namespace |
| } // namespace net |