nsswitch_reader_unittest.cc 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594
  1. // Copyright 2021 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "net/dns/nsswitch_reader.h"
  5. #include <string>
  6. #include <utility>
  7. #include <vector>
  8. #include "base/bind.h"
  9. #include "base/check.h"
  10. #include "testing/gmock/include/gmock/gmock.h"
  11. #include "testing/gtest/include/gtest/gtest.h"
  12. namespace net {
  13. namespace {
  14. class TestFileReader {
  15. public:
  16. explicit TestFileReader(std::string text) : text_(std::move(text)) {}
  17. TestFileReader(const TestFileReader&) = delete;
  18. TestFileReader& operator=(const TestFileReader&) = delete;
  19. NsswitchReader::FileReadCall GetFileReadCall() {
  20. return base::BindRepeating(&TestFileReader::ReadFile,
  21. base::Unretained(this));
  22. }
  23. std::string ReadFile() {
  24. CHECK(!already_read_);
  25. already_read_ = true;
  26. return text_;
  27. }
  28. private:
  29. std::string text_;
  30. bool already_read_ = false;
  31. };
  32. class NsswitchReaderTest : public testing::Test {
  33. public:
  34. NsswitchReaderTest() = default;
  35. NsswitchReaderTest(const NsswitchReaderTest&) = delete;
  36. NsswitchReaderTest& operator=(const NsswitchReaderTest&) = delete;
  37. protected:
  38. NsswitchReader reader_;
  39. };
  40. // Attempt to load the actual nsswitch.conf for the test machine and run
  41. // rationality checks for the result.
  42. TEST_F(NsswitchReaderTest, ActualReadAndParseHosts) {
  43. std::vector<NsswitchReader::ServiceSpecification> services =
  44. reader_.ReadAndParseHosts();
  45. // Assume nobody will ever run this on a machine with more than 1000
  46. // configured services.
  47. EXPECT_THAT(services, testing::SizeIs(testing::Le(1000u)));
  48. // Assume no service will ever have more than 10 configured actions per
  49. // service.
  50. for (const NsswitchReader::ServiceSpecification& service : services) {
  51. EXPECT_THAT(service.actions, testing::SizeIs(testing::Le(10u)));
  52. }
  53. }
  54. TEST_F(NsswitchReaderTest, FileReadErrorResultsInDefault) {
  55. TestFileReader file_reader("");
  56. reader_.set_file_read_call_for_testing(file_reader.GetFileReadCall());
  57. std::vector<NsswitchReader::ServiceSpecification> services =
  58. reader_.ReadAndParseHosts();
  59. // Expect "files dns".
  60. EXPECT_THAT(
  61. services,
  62. testing::ElementsAre(
  63. NsswitchReader::ServiceSpecification(NsswitchReader::Service::kFiles),
  64. NsswitchReader::ServiceSpecification(NsswitchReader::Service::kDns)));
  65. }
  66. TEST_F(NsswitchReaderTest, MissingHostsResultsInDefault) {
  67. const std::string kFile =
  68. "passwd: files ldap\nshadow: files\ngroup: files ldap\n";
  69. TestFileReader file_reader(kFile);
  70. reader_.set_file_read_call_for_testing(file_reader.GetFileReadCall());
  71. std::vector<NsswitchReader::ServiceSpecification> services =
  72. reader_.ReadAndParseHosts();
  73. // Expect "files dns".
  74. EXPECT_THAT(
  75. services,
  76. testing::ElementsAre(
  77. NsswitchReader::ServiceSpecification(NsswitchReader::Service::kFiles),
  78. NsswitchReader::ServiceSpecification(NsswitchReader::Service::kDns)));
  79. }
  80. TEST_F(NsswitchReaderTest, ParsesAllKnownServices) {
  81. const std::string kFile =
  82. "hosts: files dns mdns mdns4 mdns6 mdns_minimal mdns4_minimal "
  83. "mdns6_minimal myhostname resolve nis";
  84. TestFileReader file_reader(kFile);
  85. reader_.set_file_read_call_for_testing(file_reader.GetFileReadCall());
  86. std::vector<NsswitchReader::ServiceSpecification> services =
  87. reader_.ReadAndParseHosts();
  88. EXPECT_THAT(
  89. services,
  90. testing::ElementsAre(
  91. NsswitchReader::ServiceSpecification(NsswitchReader::Service::kFiles),
  92. NsswitchReader::ServiceSpecification(NsswitchReader::Service::kDns),
  93. NsswitchReader::ServiceSpecification(NsswitchReader::Service::kMdns),
  94. NsswitchReader::ServiceSpecification(NsswitchReader::Service::kMdns4),
  95. NsswitchReader::ServiceSpecification(NsswitchReader::Service::kMdns6),
  96. NsswitchReader::ServiceSpecification(
  97. NsswitchReader::Service::kMdnsMinimal),
  98. NsswitchReader::ServiceSpecification(
  99. NsswitchReader::Service::kMdns4Minimal),
  100. NsswitchReader::ServiceSpecification(
  101. NsswitchReader::Service::kMdns6Minimal),
  102. NsswitchReader::ServiceSpecification(
  103. NsswitchReader::Service::kMyHostname),
  104. NsswitchReader::ServiceSpecification(
  105. NsswitchReader::Service::kResolve),
  106. NsswitchReader::ServiceSpecification(NsswitchReader::Service::kNis)));
  107. }
  108. TEST_F(NsswitchReaderTest, ParsesRepeatedServices) {
  109. const std::string kFile = "hosts: mdns4 mdns6 mdns6 myhostname";
  110. TestFileReader file_reader(kFile);
  111. reader_.set_file_read_call_for_testing(file_reader.GetFileReadCall());
  112. std::vector<NsswitchReader::ServiceSpecification> services =
  113. reader_.ReadAndParseHosts();
  114. EXPECT_THAT(
  115. services,
  116. testing::ElementsAre(
  117. NsswitchReader::ServiceSpecification(NsswitchReader::Service::kMdns4),
  118. NsswitchReader::ServiceSpecification(NsswitchReader::Service::kMdns6),
  119. NsswitchReader::ServiceSpecification(NsswitchReader::Service::kMdns6),
  120. NsswitchReader::ServiceSpecification(
  121. NsswitchReader::Service::kMyHostname)));
  122. }
  123. TEST_F(NsswitchReaderTest, ParsesAllKnownActions) {
  124. const std::string kFile =
  125. "hosts: files [UNAVAIL=RETURN] [UNAVAIL=CONTINUE] [UNAVAIL=MERGE]";
  126. TestFileReader file_reader(kFile);
  127. reader_.set_file_read_call_for_testing(file_reader.GetFileReadCall());
  128. std::vector<NsswitchReader::ServiceSpecification> services =
  129. reader_.ReadAndParseHosts();
  130. EXPECT_THAT(services,
  131. testing::ElementsAre(NsswitchReader::ServiceSpecification(
  132. NsswitchReader::Service::kFiles,
  133. {{/*negated=*/false, NsswitchReader::Status::kUnavailable,
  134. NsswitchReader::Action::kReturn},
  135. {/*negated=*/false, NsswitchReader::Status::kUnavailable,
  136. NsswitchReader::Action::kContinue},
  137. {/*negated=*/false, NsswitchReader::Status::kUnavailable,
  138. NsswitchReader::Action::kMerge}})));
  139. }
  140. TEST_F(NsswitchReaderTest, ParsesAllKnownStatuses) {
  141. const std::string kFile =
  142. "hosts: dns [SUCCESS=RETURN] [NOTFOUND=RETURN] [UNAVAIL=RETURN] "
  143. "[TRYAGAIN=RETURN]";
  144. TestFileReader file_reader(kFile);
  145. reader_.set_file_read_call_for_testing(file_reader.GetFileReadCall());
  146. std::vector<NsswitchReader::ServiceSpecification> services =
  147. reader_.ReadAndParseHosts();
  148. EXPECT_THAT(services,
  149. testing::ElementsAre(NsswitchReader::ServiceSpecification(
  150. NsswitchReader::Service::kDns,
  151. {{/*negated=*/false, NsswitchReader::Status::kSuccess,
  152. NsswitchReader::Action::kReturn},
  153. {/*negated=*/false, NsswitchReader::Status::kNotFound,
  154. NsswitchReader::Action::kReturn},
  155. {/*negated=*/false, NsswitchReader::Status::kUnavailable,
  156. NsswitchReader::Action::kReturn},
  157. {/*negated=*/false, NsswitchReader::Status::kTryAgain,
  158. NsswitchReader::Action::kReturn}})));
  159. }
  160. TEST_F(NsswitchReaderTest, ParsesRepeatedActions) {
  161. const std::string kFile =
  162. "hosts: nis [!SUCCESS=RETURN] [NOTFOUND=RETURN] [NOTFOUND=RETURN] "
  163. "[!UNAVAIL=RETURN]";
  164. TestFileReader file_reader(kFile);
  165. reader_.set_file_read_call_for_testing(file_reader.GetFileReadCall());
  166. std::vector<NsswitchReader::ServiceSpecification> services =
  167. reader_.ReadAndParseHosts();
  168. EXPECT_THAT(services,
  169. testing::ElementsAre(NsswitchReader::ServiceSpecification(
  170. NsswitchReader::Service::kNis,
  171. {{/*negated=*/true, NsswitchReader::Status::kSuccess,
  172. NsswitchReader::Action::kReturn},
  173. {/*negated=*/false, NsswitchReader::Status::kNotFound,
  174. NsswitchReader::Action::kReturn},
  175. {/*negated=*/false, NsswitchReader::Status::kNotFound,
  176. NsswitchReader::Action::kReturn},
  177. {/*negated=*/true, NsswitchReader::Status::kUnavailable,
  178. NsswitchReader::Action::kReturn}})));
  179. }
  180. TEST_F(NsswitchReaderTest, ParsesCombinedActionLists) {
  181. const std::string kFile =
  182. "hosts: dns [SUCCESS=RETURN !NOTFOUND=RETURN UNAVAIL=RETURN] files";
  183. TestFileReader file_reader(kFile);
  184. reader_.set_file_read_call_for_testing(file_reader.GetFileReadCall());
  185. std::vector<NsswitchReader::ServiceSpecification> services =
  186. reader_.ReadAndParseHosts();
  187. EXPECT_THAT(services,
  188. testing::ElementsAre(
  189. NsswitchReader::ServiceSpecification(
  190. NsswitchReader::Service::kDns,
  191. {{/*negated=*/false, NsswitchReader::Status::kSuccess,
  192. NsswitchReader::Action::kReturn},
  193. {/*negated=*/true, NsswitchReader::Status::kNotFound,
  194. NsswitchReader::Action::kReturn},
  195. {/*negated=*/false, NsswitchReader::Status::kUnavailable,
  196. NsswitchReader::Action::kReturn}}),
  197. NsswitchReader::ServiceSpecification(
  198. NsswitchReader::Service::kFiles)));
  199. }
  200. TEST_F(NsswitchReaderTest, HandlesAtypicalWhitespace) {
  201. const std::string kFile =
  202. " database: service \n\n hosts: files\tdns mdns4 \t mdns6 \t "
  203. "\t\n\t\n";
  204. TestFileReader file_reader(kFile);
  205. reader_.set_file_read_call_for_testing(file_reader.GetFileReadCall());
  206. std::vector<NsswitchReader::ServiceSpecification> services =
  207. reader_.ReadAndParseHosts();
  208. EXPECT_THAT(
  209. services,
  210. testing::ElementsAre(
  211. NsswitchReader::ServiceSpecification(NsswitchReader::Service::kFiles),
  212. NsswitchReader::ServiceSpecification(NsswitchReader::Service::kDns),
  213. NsswitchReader::ServiceSpecification(NsswitchReader::Service::kMdns4),
  214. NsswitchReader::ServiceSpecification(
  215. NsswitchReader::Service::kMdns6)));
  216. }
  217. TEST_F(NsswitchReaderTest, HandlesAtypicalWhitespaceInActions) {
  218. const std::string kFile =
  219. "hosts: dns [ !UNAVAIL=MERGE \t NOTFOUND=RETURN\t][ UNAVAIL=CONTINUE]";
  220. TestFileReader file_reader(kFile);
  221. reader_.set_file_read_call_for_testing(file_reader.GetFileReadCall());
  222. std::vector<NsswitchReader::ServiceSpecification> services =
  223. reader_.ReadAndParseHosts();
  224. EXPECT_THAT(services,
  225. testing::ElementsAre(NsswitchReader::ServiceSpecification(
  226. NsswitchReader::Service::kDns,
  227. {{/*negated=*/true, NsswitchReader::Status::kUnavailable,
  228. NsswitchReader::Action::kMerge},
  229. {/*negated=*/false, NsswitchReader::Status::kNotFound,
  230. NsswitchReader::Action::kReturn},
  231. {/*negated=*/false, NsswitchReader::Status::kUnavailable,
  232. NsswitchReader::Action::kContinue}})));
  233. }
  234. TEST_F(NsswitchReaderTest, ParsesActionsWithoutService) {
  235. const std::string kFile = "hosts: [SUCCESS=RETURN]";
  236. TestFileReader file_reader(kFile);
  237. reader_.set_file_read_call_for_testing(file_reader.GetFileReadCall());
  238. std::vector<NsswitchReader::ServiceSpecification> services =
  239. reader_.ReadAndParseHosts();
  240. EXPECT_THAT(services,
  241. testing::ElementsAre(NsswitchReader::ServiceSpecification(
  242. NsswitchReader::Service::kUnknown,
  243. {{/*negated=*/false, NsswitchReader::Status::kSuccess,
  244. NsswitchReader::Action::kReturn}})));
  245. }
  246. TEST_F(NsswitchReaderTest, ParsesNegatedActions) {
  247. const std::string kFile =
  248. "hosts: mdns_minimal [!UNAVAIL=RETURN] [NOTFOUND=CONTINUE] "
  249. "[!TRYAGAIN=CONTINUE]";
  250. TestFileReader file_reader(kFile);
  251. reader_.set_file_read_call_for_testing(file_reader.GetFileReadCall());
  252. std::vector<NsswitchReader::ServiceSpecification> services =
  253. reader_.ReadAndParseHosts();
  254. EXPECT_THAT(services,
  255. testing::ElementsAre(NsswitchReader::ServiceSpecification(
  256. NsswitchReader::Service::kMdnsMinimal,
  257. {{/*negated=*/true, NsswitchReader::Status::kUnavailable,
  258. NsswitchReader::Action::kReturn},
  259. {/*negated=*/false, NsswitchReader::Status::kNotFound,
  260. NsswitchReader::Action::kContinue},
  261. {/*negated=*/true, NsswitchReader::Status::kTryAgain,
  262. NsswitchReader::Action::kContinue}})));
  263. }
  264. TEST_F(NsswitchReaderTest, ParsesUnrecognizedServiceAsUnknown) {
  265. const std::string kFile =
  266. "passwd: files\nhosts: files super_awesome_service myhostname";
  267. TestFileReader file_reader(kFile);
  268. reader_.set_file_read_call_for_testing(file_reader.GetFileReadCall());
  269. std::vector<NsswitchReader::ServiceSpecification> services =
  270. reader_.ReadAndParseHosts();
  271. EXPECT_THAT(services,
  272. testing::ElementsAre(NsswitchReader::ServiceSpecification(
  273. NsswitchReader::Service::kFiles),
  274. NsswitchReader::ServiceSpecification(
  275. NsswitchReader::Service::kUnknown),
  276. NsswitchReader::ServiceSpecification(
  277. NsswitchReader::Service::kMyHostname)));
  278. }
  279. TEST_F(NsswitchReaderTest, ParsesUnrecognizedStatusAsUnknown) {
  280. const std::string kFile =
  281. "hosts: nis [HELLO=CONTINUE]\nshadow: service\ndatabase: cheese";
  282. TestFileReader file_reader(kFile);
  283. reader_.set_file_read_call_for_testing(file_reader.GetFileReadCall());
  284. std::vector<NsswitchReader::ServiceSpecification> services =
  285. reader_.ReadAndParseHosts();
  286. EXPECT_THAT(services,
  287. testing::ElementsAre(NsswitchReader::ServiceSpecification(
  288. NsswitchReader::Service::kNis,
  289. {{/*negated=*/false, NsswitchReader::Status::kUnknown,
  290. NsswitchReader::Action::kContinue}})));
  291. }
  292. TEST_F(NsswitchReaderTest, ParsesUnrecognizedActionAsUnknown) {
  293. const std::string kFile =
  294. "more: service\nhosts: mdns6 [!UNAVAIL=HI]\nshadow: service";
  295. TestFileReader file_reader(kFile);
  296. reader_.set_file_read_call_for_testing(file_reader.GetFileReadCall());
  297. std::vector<NsswitchReader::ServiceSpecification> services =
  298. reader_.ReadAndParseHosts();
  299. EXPECT_THAT(services,
  300. testing::ElementsAre(NsswitchReader::ServiceSpecification(
  301. NsswitchReader::Service::kMdns6,
  302. {{/*negated=*/true, NsswitchReader::Status::kUnavailable,
  303. NsswitchReader::Action::kUnknown}})));
  304. }
  305. TEST_F(NsswitchReaderTest, ParsesInvalidActionsAsUnknown) {
  306. const std::string kFile = "hosts: mdns_minimal [a=b=c] nis";
  307. TestFileReader file_reader(kFile);
  308. reader_.set_file_read_call_for_testing(file_reader.GetFileReadCall());
  309. std::vector<NsswitchReader::ServiceSpecification> services =
  310. reader_.ReadAndParseHosts();
  311. EXPECT_THAT(
  312. services,
  313. testing::ElementsAre(
  314. NsswitchReader::ServiceSpecification(
  315. NsswitchReader::Service::kMdnsMinimal,
  316. {{/*negated=*/false, NsswitchReader::Status::kUnknown,
  317. NsswitchReader::Action::kUnknown}}),
  318. NsswitchReader::ServiceSpecification(NsswitchReader::Service::kNis)));
  319. }
  320. TEST_F(NsswitchReaderTest, IgnoresInvalidlyClosedActions) {
  321. const std::string kFile = "hosts: myhostname [SUCCESS=MERGE";
  322. TestFileReader file_reader(kFile);
  323. reader_.set_file_read_call_for_testing(file_reader.GetFileReadCall());
  324. std::vector<NsswitchReader::ServiceSpecification> services =
  325. reader_.ReadAndParseHosts();
  326. EXPECT_THAT(services,
  327. testing::ElementsAre(NsswitchReader::ServiceSpecification(
  328. NsswitchReader::Service::kMyHostname,
  329. {{/*negated=*/false, NsswitchReader::Status::kSuccess,
  330. NsswitchReader::Action::kMerge}})));
  331. }
  332. TEST_F(NsswitchReaderTest, ParsesServicesAfterInvalidlyClosedActionsAsUnknown) {
  333. const std::string kFile = "hosts: resolve [SUCCESS=CONTINUE dns";
  334. TestFileReader file_reader(kFile);
  335. reader_.set_file_read_call_for_testing(file_reader.GetFileReadCall());
  336. std::vector<NsswitchReader::ServiceSpecification> services =
  337. reader_.ReadAndParseHosts();
  338. EXPECT_THAT(services,
  339. testing::ElementsAre(NsswitchReader::ServiceSpecification(
  340. NsswitchReader::Service::kResolve,
  341. {{/*negated=*/false, NsswitchReader::Status::kSuccess,
  342. NsswitchReader::Action::kContinue},
  343. {/*negated=*/false, NsswitchReader::Status::kUnknown,
  344. NsswitchReader::Action::kUnknown}})));
  345. }
  346. TEST_F(NsswitchReaderTest, IgnoresComments) {
  347. const std::string kFile =
  348. "#hosts: files super_awesome_service myhostname\nnetmask: service";
  349. TestFileReader file_reader(kFile);
  350. reader_.set_file_read_call_for_testing(file_reader.GetFileReadCall());
  351. std::vector<NsswitchReader::ServiceSpecification> services =
  352. reader_.ReadAndParseHosts();
  353. // Expect "files dns" due to not finding an uncommented "hosts:" row.
  354. EXPECT_THAT(
  355. services,
  356. testing::ElementsAre(
  357. NsswitchReader::ServiceSpecification(NsswitchReader::Service::kFiles),
  358. NsswitchReader::ServiceSpecification(NsswitchReader::Service::kDns)));
  359. }
  360. TEST_F(NsswitchReaderTest, IgnoresEndOfLineComments) {
  361. const std::string kFile =
  362. "hosts: files super_awesome_service myhostname # dns";
  363. TestFileReader file_reader(kFile);
  364. reader_.set_file_read_call_for_testing(file_reader.GetFileReadCall());
  365. std::vector<NsswitchReader::ServiceSpecification> services =
  366. reader_.ReadAndParseHosts();
  367. EXPECT_THAT(services,
  368. testing::ElementsAre(NsswitchReader::ServiceSpecification(
  369. NsswitchReader::Service::kFiles),
  370. NsswitchReader::ServiceSpecification(
  371. NsswitchReader::Service::kUnknown),
  372. NsswitchReader::ServiceSpecification(
  373. NsswitchReader::Service::kMyHostname)));
  374. }
  375. TEST_F(NsswitchReaderTest, IgnoresCapitalization) {
  376. const std::string kFile = "HoStS: mDNS6 [!uNaVaIl=MeRgE]";
  377. TestFileReader file_reader(kFile);
  378. reader_.set_file_read_call_for_testing(file_reader.GetFileReadCall());
  379. std::vector<NsswitchReader::ServiceSpecification> services =
  380. reader_.ReadAndParseHosts();
  381. EXPECT_THAT(services,
  382. testing::ElementsAre(NsswitchReader::ServiceSpecification(
  383. NsswitchReader::Service::kMdns6,
  384. {{/*negated=*/true, NsswitchReader::Status::kUnavailable,
  385. NsswitchReader::Action::kMerge}})));
  386. }
  387. TEST_F(NsswitchReaderTest, IgnoresEmptyActions) {
  388. const std::string kFile = "hosts: mdns_minimal [ \t ][] [ ]";
  389. TestFileReader file_reader(kFile);
  390. reader_.set_file_read_call_for_testing(file_reader.GetFileReadCall());
  391. std::vector<NsswitchReader::ServiceSpecification> services =
  392. reader_.ReadAndParseHosts();
  393. EXPECT_THAT(services,
  394. testing::ElementsAre(NsswitchReader::ServiceSpecification(
  395. NsswitchReader::Service::kMdnsMinimal)));
  396. }
  397. TEST_F(NsswitchReaderTest, IgnoresRepeatedActionBrackets) {
  398. const std::string kFile = "hosts: mdns [[SUCCESS=RETURN]]]dns";
  399. TestFileReader file_reader(kFile);
  400. reader_.set_file_read_call_for_testing(file_reader.GetFileReadCall());
  401. std::vector<NsswitchReader::ServiceSpecification> services =
  402. reader_.ReadAndParseHosts();
  403. EXPECT_THAT(
  404. services,
  405. testing::ElementsAre(
  406. NsswitchReader::ServiceSpecification(
  407. NsswitchReader::Service::kMdns,
  408. {{/*negated=*/false, NsswitchReader::Status::kSuccess,
  409. NsswitchReader::Action::kReturn}}),
  410. NsswitchReader::ServiceSpecification(NsswitchReader::Service::kDns)));
  411. }
  412. TEST_F(NsswitchReaderTest, IgnoresRepeatedActionBracketsWithWhitespace) {
  413. const std::string kFile = "hosts: mdns [ [ SUCCESS=RETURN ]\t] ]\t mdns6";
  414. TestFileReader file_reader(kFile);
  415. reader_.set_file_read_call_for_testing(file_reader.GetFileReadCall());
  416. std::vector<NsswitchReader::ServiceSpecification> services =
  417. reader_.ReadAndParseHosts();
  418. EXPECT_THAT(services,
  419. testing::ElementsAre(
  420. NsswitchReader::ServiceSpecification(
  421. NsswitchReader::Service::kMdns,
  422. {{/*negated=*/false, NsswitchReader::Status::kSuccess,
  423. NsswitchReader::Action::kReturn}}),
  424. NsswitchReader::ServiceSpecification(
  425. NsswitchReader::Service::kMdns6)));
  426. }
  427. TEST_F(NsswitchReaderTest, RejectsNonSensicalActionBrackets) {
  428. const std::string kFile = "hosts: mdns4 [UNAVAIL[=MERGE]]";
  429. TestFileReader file_reader(kFile);
  430. reader_.set_file_read_call_for_testing(file_reader.GetFileReadCall());
  431. std::vector<NsswitchReader::ServiceSpecification> services =
  432. reader_.ReadAndParseHosts();
  433. EXPECT_THAT(services,
  434. testing::ElementsAre(NsswitchReader::ServiceSpecification(
  435. NsswitchReader::Service::kMdns4,
  436. {{/*negated=*/false, NsswitchReader::Status::kUnknown,
  437. NsswitchReader::Action::kMerge}})));
  438. }
  439. TEST_F(NsswitchReaderTest, RejectsServicesWithBrackets) {
  440. const std::string kFile = "hosts: se]r[vice[name";
  441. TestFileReader file_reader(kFile);
  442. reader_.set_file_read_call_for_testing(file_reader.GetFileReadCall());
  443. std::vector<NsswitchReader::ServiceSpecification> services =
  444. reader_.ReadAndParseHosts();
  445. EXPECT_THAT(services,
  446. testing::ElementsAre(NsswitchReader::ServiceSpecification(
  447. NsswitchReader::Service::kUnknown)));
  448. }
  449. // Other than the case of repeating opening brackets, nested brackets are not
  450. // valid and should just get treated as part of an action label.
  451. TEST_F(NsswitchReaderTest, RejectsNestedActionBrackets) {
  452. const std::string kFile =
  453. "hosts: nis [SUCCESS=RETURN [NOTFOUND=CONTINUE] UNAVAIL=MERGE]";
  454. TestFileReader file_reader(kFile);
  455. reader_.set_file_read_call_for_testing(file_reader.GetFileReadCall());
  456. std::vector<NsswitchReader::ServiceSpecification> services =
  457. reader_.ReadAndParseHosts();
  458. EXPECT_THAT(services,
  459. testing::ElementsAre(
  460. NsswitchReader::ServiceSpecification(
  461. NsswitchReader::Service::kNis,
  462. {{/*negated=*/false, NsswitchReader::Status::kSuccess,
  463. NsswitchReader::Action::kReturn},
  464. {/*negated=*/false, NsswitchReader::Status::kUnknown,
  465. NsswitchReader::Action::kContinue}}),
  466. NsswitchReader::ServiceSpecification(
  467. NsswitchReader::Service::kUnknown)));
  468. }
  469. TEST_F(NsswitchReaderTest, IgnoresEmptyActionWithRepeatedBrackets) {
  470. const std::string kFile = "hosts: files [[[]]]] mdns";
  471. TestFileReader file_reader(kFile);
  472. reader_.set_file_read_call_for_testing(file_reader.GetFileReadCall());
  473. std::vector<NsswitchReader::ServiceSpecification> services =
  474. reader_.ReadAndParseHosts();
  475. EXPECT_THAT(services,
  476. testing::ElementsAre(NsswitchReader::ServiceSpecification(
  477. NsswitchReader::Service::kFiles),
  478. NsswitchReader::ServiceSpecification(
  479. NsswitchReader::Service::kMdns)));
  480. }
  481. TEST_F(NsswitchReaderTest, IgnoresEmptyActionAtEndOfString) {
  482. const std::string kFile = "hosts: dns [[";
  483. TestFileReader file_reader(kFile);
  484. reader_.set_file_read_call_for_testing(file_reader.GetFileReadCall());
  485. std::vector<NsswitchReader::ServiceSpecification> services =
  486. reader_.ReadAndParseHosts();
  487. EXPECT_THAT(services,
  488. testing::ElementsAre(NsswitchReader::ServiceSpecification(
  489. NsswitchReader::Service::kDns)));
  490. }
  491. } // namespace
  492. } // namespace net