/thirdparty/breakpad/third_party/protobuf/protobuf/src/google/protobuf/compiler/importer_unittest.cc

http://github.com/tomahawk-player/tomahawk · C++ · 600 lines · 416 code · 99 blank · 85 comment · 26 complexity · 7bf0d96636e10addb68389f50200a4c7 MD5 · raw file

  1. // Protocol Buffers - Google's data interchange format
  2. // Copyright 2008 Google Inc. All rights reserved.
  3. // http://code.google.com/p/protobuf/
  4. //
  5. // Redistribution and use in source and binary forms, with or without
  6. // modification, are permitted provided that the following conditions are
  7. // met:
  8. //
  9. // * Redistributions of source code must retain the above copyright
  10. // notice, this list of conditions and the following disclaimer.
  11. // * Redistributions in binary form must reproduce the above
  12. // copyright notice, this list of conditions and the following disclaimer
  13. // in the documentation and/or other materials provided with the
  14. // distribution.
  15. // * Neither the name of Google Inc. nor the names of its
  16. // contributors may be used to endorse or promote products derived from
  17. // this software without specific prior written permission.
  18. //
  19. // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  20. // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  21. // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  22. // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  23. // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  24. // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  25. // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  26. // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  27. // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  28. // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  29. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  30. // Author: kenton@google.com (Kenton Varda)
  31. // Based on original Protocol Buffers design by
  32. // Sanjay Ghemawat, Jeff Dean, and others.
  33. #include <google/protobuf/stubs/hash.h>
  34. #include <google/protobuf/compiler/importer.h>
  35. #include <google/protobuf/descriptor.h>
  36. #include <google/protobuf/io/zero_copy_stream_impl.h>
  37. #include <google/protobuf/stubs/map-util.h>
  38. #include <google/protobuf/stubs/common.h>
  39. #include <google/protobuf/testing/file.h>
  40. #include <google/protobuf/stubs/strutil.h>
  41. #include <google/protobuf/stubs/substitute.h>
  42. #include <google/protobuf/testing/googletest.h>
  43. #include <gtest/gtest.h>
  44. namespace google {
  45. namespace protobuf {
  46. namespace compiler {
  47. namespace {
  48. #define EXPECT_SUBSTRING(needle, haystack) \
  49. EXPECT_PRED_FORMAT2(testing::IsSubstring, (needle), (haystack))
  50. class MockErrorCollector : public MultiFileErrorCollector {
  51. public:
  52. MockErrorCollector() {}
  53. ~MockErrorCollector() {}
  54. string text_;
  55. // implements ErrorCollector ---------------------------------------
  56. void AddError(const string& filename, int line, int column,
  57. const string& message) {
  58. strings::SubstituteAndAppend(&text_, "$0:$1:$2: $3\n",
  59. filename, line, column, message);
  60. }
  61. };
  62. // -------------------------------------------------------------------
  63. // A dummy implementation of SourceTree backed by a simple map.
  64. class MockSourceTree : public SourceTree {
  65. public:
  66. MockSourceTree() {}
  67. ~MockSourceTree() {}
  68. void AddFile(const string& name, const char* contents) {
  69. files_[name] = contents;
  70. }
  71. // implements SourceTree -------------------------------------------
  72. io::ZeroCopyInputStream* Open(const string& filename) {
  73. const char* contents = FindPtrOrNull(files_, filename);
  74. if (contents == NULL) {
  75. return NULL;
  76. } else {
  77. return new io::ArrayInputStream(contents, strlen(contents));
  78. }
  79. }
  80. private:
  81. hash_map<string, const char*> files_;
  82. };
  83. // ===================================================================
  84. class ImporterTest : public testing::Test {
  85. protected:
  86. ImporterTest()
  87. : importer_(&source_tree_, &error_collector_) {}
  88. void AddFile(const string& filename, const char* text) {
  89. source_tree_.AddFile(filename, text);
  90. }
  91. // Return the collected error text
  92. string error() const { return error_collector_.text_; }
  93. MockErrorCollector error_collector_;
  94. MockSourceTree source_tree_;
  95. Importer importer_;
  96. };
  97. TEST_F(ImporterTest, Import) {
  98. // Test normal importing.
  99. AddFile("foo.proto",
  100. "syntax = \"proto2\";\n"
  101. "message Foo {}\n");
  102. const FileDescriptor* file = importer_.Import("foo.proto");
  103. EXPECT_EQ("", error_collector_.text_);
  104. ASSERT_TRUE(file != NULL);
  105. ASSERT_EQ(1, file->message_type_count());
  106. EXPECT_EQ("Foo", file->message_type(0)->name());
  107. // Importing again should return same object.
  108. EXPECT_EQ(file, importer_.Import("foo.proto"));
  109. }
  110. TEST_F(ImporterTest, ImportNested) {
  111. // Test that importing a file which imports another file works.
  112. AddFile("foo.proto",
  113. "syntax = \"proto2\";\n"
  114. "import \"bar.proto\";\n"
  115. "message Foo {\n"
  116. " optional Bar bar = 1;\n"
  117. "}\n");
  118. AddFile("bar.proto",
  119. "syntax = \"proto2\";\n"
  120. "message Bar {}\n");
  121. // Note that both files are actually parsed by the first call to Import()
  122. // here, since foo.proto imports bar.proto. The second call just returns
  123. // the same ProtoFile for bar.proto which was constructed while importing
  124. // foo.proto. We test that this is the case below by checking that bar
  125. // is among foo's dependencies (by pointer).
  126. const FileDescriptor* foo = importer_.Import("foo.proto");
  127. const FileDescriptor* bar = importer_.Import("bar.proto");
  128. EXPECT_EQ("", error_collector_.text_);
  129. ASSERT_TRUE(foo != NULL);
  130. ASSERT_TRUE(bar != NULL);
  131. // Check that foo's dependency is the same object as bar.
  132. ASSERT_EQ(1, foo->dependency_count());
  133. EXPECT_EQ(bar, foo->dependency(0));
  134. // Check that foo properly cross-links bar.
  135. ASSERT_EQ(1, foo->message_type_count());
  136. ASSERT_EQ(1, bar->message_type_count());
  137. ASSERT_EQ(1, foo->message_type(0)->field_count());
  138. ASSERT_EQ(FieldDescriptor::TYPE_MESSAGE,
  139. foo->message_type(0)->field(0)->type());
  140. EXPECT_EQ(bar->message_type(0),
  141. foo->message_type(0)->field(0)->message_type());
  142. }
  143. TEST_F(ImporterTest, FileNotFound) {
  144. // Error: Parsing a file that doesn't exist.
  145. EXPECT_TRUE(importer_.Import("foo.proto") == NULL);
  146. EXPECT_EQ(
  147. "foo.proto:-1:0: File not found.\n",
  148. error_collector_.text_);
  149. }
  150. TEST_F(ImporterTest, ImportNotFound) {
  151. // Error: Importing a file that doesn't exist.
  152. AddFile("foo.proto",
  153. "syntax = \"proto2\";\n"
  154. "import \"bar.proto\";\n");
  155. EXPECT_TRUE(importer_.Import("foo.proto") == NULL);
  156. EXPECT_EQ(
  157. "bar.proto:-1:0: File not found.\n"
  158. "foo.proto:-1:0: Import \"bar.proto\" was not found or had errors.\n",
  159. error_collector_.text_);
  160. }
  161. TEST_F(ImporterTest, RecursiveImport) {
  162. // Error: Recursive import.
  163. AddFile("recursive1.proto",
  164. "syntax = \"proto2\";\n"
  165. "import \"recursive2.proto\";\n");
  166. AddFile("recursive2.proto",
  167. "syntax = \"proto2\";\n"
  168. "import \"recursive1.proto\";\n");
  169. EXPECT_TRUE(importer_.Import("recursive1.proto") == NULL);
  170. EXPECT_EQ(
  171. "recursive1.proto:-1:0: File recursively imports itself: recursive1.proto "
  172. "-> recursive2.proto -> recursive1.proto\n"
  173. "recursive2.proto:-1:0: Import \"recursive1.proto\" was not found "
  174. "or had errors.\n"
  175. "recursive1.proto:-1:0: Import \"recursive2.proto\" was not found "
  176. "or had errors.\n",
  177. error_collector_.text_);
  178. }
  179. // TODO(sanjay): The MapField tests below more properly belong in
  180. // descriptor_unittest, but are more convenient to test here.
  181. TEST_F(ImporterTest, MapFieldValid) {
  182. AddFile(
  183. "map.proto",
  184. "syntax = \"proto2\";\n"
  185. "message Item {\n"
  186. " required string key = 1;\n"
  187. "}\n"
  188. "message Map {\n"
  189. " repeated Item items = 1 [experimental_map_key = \"key\"];\n"
  190. "}\n"
  191. );
  192. const FileDescriptor* file = importer_.Import("map.proto");
  193. ASSERT_TRUE(file != NULL) << error_collector_.text_;
  194. EXPECT_EQ("", error_collector_.text_);
  195. // Check that Map::items points to Item::key
  196. const Descriptor* item_type = file->FindMessageTypeByName("Item");
  197. ASSERT_TRUE(item_type != NULL);
  198. const Descriptor* map_type = file->FindMessageTypeByName("Map");
  199. ASSERT_TRUE(map_type != NULL);
  200. const FieldDescriptor* key_field = item_type->FindFieldByName("key");
  201. ASSERT_TRUE(key_field != NULL);
  202. const FieldDescriptor* items_field = map_type->FindFieldByName("items");
  203. ASSERT_TRUE(items_field != NULL);
  204. EXPECT_EQ(items_field->experimental_map_key(), key_field);
  205. }
  206. TEST_F(ImporterTest, MapFieldNotRepeated) {
  207. AddFile(
  208. "map.proto",
  209. "syntax = \"proto2\";\n"
  210. "message Item {\n"
  211. " required string key = 1;\n"
  212. "}\n"
  213. "message Map {\n"
  214. " required Item items = 1 [experimental_map_key = \"key\"];\n"
  215. "}\n"
  216. );
  217. EXPECT_TRUE(importer_.Import("map.proto") == NULL);
  218. EXPECT_SUBSTRING("only allowed for repeated fields", error());
  219. }
  220. TEST_F(ImporterTest, MapFieldNotMessageType) {
  221. AddFile(
  222. "map.proto",
  223. "syntax = \"proto2\";\n"
  224. "message Map {\n"
  225. " repeated int32 items = 1 [experimental_map_key = \"key\"];\n"
  226. "}\n"
  227. );
  228. EXPECT_TRUE(importer_.Import("map.proto") == NULL);
  229. EXPECT_SUBSTRING("only allowed for fields with a message type", error());
  230. }
  231. TEST_F(ImporterTest, MapFieldTypeNotFound) {
  232. AddFile(
  233. "map.proto",
  234. "syntax = \"proto2\";\n"
  235. "message Map {\n"
  236. " repeated Unknown items = 1 [experimental_map_key = \"key\"];\n"
  237. "}\n"
  238. );
  239. EXPECT_TRUE(importer_.Import("map.proto") == NULL);
  240. EXPECT_SUBSTRING("not defined", error());
  241. }
  242. TEST_F(ImporterTest, MapFieldKeyNotFound) {
  243. AddFile(
  244. "map.proto",
  245. "syntax = \"proto2\";\n"
  246. "message Item {\n"
  247. " required string key = 1;\n"
  248. "}\n"
  249. "message Map {\n"
  250. " repeated Item items = 1 [experimental_map_key = \"badkey\"];\n"
  251. "}\n"
  252. );
  253. EXPECT_TRUE(importer_.Import("map.proto") == NULL);
  254. EXPECT_SUBSTRING("Could not find field", error());
  255. }
  256. TEST_F(ImporterTest, MapFieldKeyRepeated) {
  257. AddFile(
  258. "map.proto",
  259. "syntax = \"proto2\";\n"
  260. "message Item {\n"
  261. " repeated string key = 1;\n"
  262. "}\n"
  263. "message Map {\n"
  264. " repeated Item items = 1 [experimental_map_key = \"key\"];\n"
  265. "}\n"
  266. );
  267. EXPECT_TRUE(importer_.Import("map.proto") == NULL);
  268. EXPECT_SUBSTRING("must not name a repeated field", error());
  269. }
  270. TEST_F(ImporterTest, MapFieldKeyNotScalar) {
  271. AddFile(
  272. "map.proto",
  273. "syntax = \"proto2\";\n"
  274. "message ItemKey { }\n"
  275. "message Item {\n"
  276. " required ItemKey key = 1;\n"
  277. "}\n"
  278. "message Map {\n"
  279. " repeated Item items = 1 [experimental_map_key = \"key\"];\n"
  280. "}\n"
  281. );
  282. EXPECT_TRUE(importer_.Import("map.proto") == NULL);
  283. EXPECT_SUBSTRING("must name a scalar or string", error());
  284. }
  285. // ===================================================================
  286. class DiskSourceTreeTest : public testing::Test {
  287. protected:
  288. virtual void SetUp() {
  289. dirnames_.push_back(TestTempDir() + "/test_proto2_import_path_1");
  290. dirnames_.push_back(TestTempDir() + "/test_proto2_import_path_2");
  291. for (int i = 0; i < dirnames_.size(); i++) {
  292. if (File::Exists(dirnames_[i])) {
  293. File::DeleteRecursively(dirnames_[i], NULL, NULL);
  294. }
  295. GOOGLE_CHECK(File::CreateDir(dirnames_[i].c_str(), DEFAULT_FILE_MODE));
  296. }
  297. }
  298. virtual void TearDown() {
  299. for (int i = 0; i < dirnames_.size(); i++) {
  300. File::DeleteRecursively(dirnames_[i], NULL, NULL);
  301. }
  302. }
  303. void AddFile(const string& filename, const char* contents) {
  304. File::WriteStringToFileOrDie(contents, filename);
  305. }
  306. void AddSubdir(const string& dirname) {
  307. GOOGLE_CHECK(File::CreateDir(dirname.c_str(), DEFAULT_FILE_MODE));
  308. }
  309. void ExpectFileContents(const string& filename,
  310. const char* expected_contents) {
  311. scoped_ptr<io::ZeroCopyInputStream> input(source_tree_.Open(filename));
  312. ASSERT_FALSE(input == NULL);
  313. // Read all the data from the file.
  314. string file_contents;
  315. const void* data;
  316. int size;
  317. while (input->Next(&data, &size)) {
  318. file_contents.append(reinterpret_cast<const char*>(data), size);
  319. }
  320. EXPECT_EQ(expected_contents, file_contents);
  321. }
  322. void ExpectFileNotFound(const string& filename) {
  323. scoped_ptr<io::ZeroCopyInputStream> input(source_tree_.Open(filename));
  324. EXPECT_TRUE(input == NULL);
  325. }
  326. DiskSourceTree source_tree_;
  327. // Paths of two on-disk directories to use during the test.
  328. vector<string> dirnames_;
  329. };
  330. TEST_F(DiskSourceTreeTest, MapRoot) {
  331. // Test opening a file in a directory that is mapped to the root of the
  332. // source tree.
  333. AddFile(dirnames_[0] + "/foo", "Hello World!");
  334. source_tree_.MapPath("", dirnames_[0]);
  335. ExpectFileContents("foo", "Hello World!");
  336. ExpectFileNotFound("bar");
  337. }
  338. TEST_F(DiskSourceTreeTest, MapDirectory) {
  339. // Test opening a file in a directory that is mapped to somewhere other
  340. // than the root of the source tree.
  341. AddFile(dirnames_[0] + "/foo", "Hello World!");
  342. source_tree_.MapPath("baz", dirnames_[0]);
  343. ExpectFileContents("baz/foo", "Hello World!");
  344. ExpectFileNotFound("baz/bar");
  345. ExpectFileNotFound("foo");
  346. ExpectFileNotFound("bar");
  347. // Non-canonical file names should not work.
  348. ExpectFileNotFound("baz//foo");
  349. ExpectFileNotFound("baz/../baz/foo");
  350. ExpectFileNotFound("baz/./foo");
  351. ExpectFileNotFound("baz/foo/");
  352. }
  353. TEST_F(DiskSourceTreeTest, NoParent) {
  354. // Test that we cannot open files in a parent of a mapped directory.
  355. AddFile(dirnames_[0] + "/foo", "Hello World!");
  356. AddSubdir(dirnames_[0] + "/bar");
  357. AddFile(dirnames_[0] + "/bar/baz", "Blah.");
  358. source_tree_.MapPath("", dirnames_[0] + "/bar");
  359. ExpectFileContents("baz", "Blah.");
  360. ExpectFileNotFound("../foo");
  361. ExpectFileNotFound("../bar/baz");
  362. }
  363. TEST_F(DiskSourceTreeTest, MapFile) {
  364. // Test opening a file that is mapped directly into the source tree.
  365. AddFile(dirnames_[0] + "/foo", "Hello World!");
  366. source_tree_.MapPath("foo", dirnames_[0] + "/foo");
  367. ExpectFileContents("foo", "Hello World!");
  368. ExpectFileNotFound("bar");
  369. }
  370. TEST_F(DiskSourceTreeTest, SearchMultipleDirectories) {
  371. // Test mapping and searching multiple directories.
  372. AddFile(dirnames_[0] + "/foo", "Hello World!");
  373. AddFile(dirnames_[1] + "/foo", "This file should be hidden.");
  374. AddFile(dirnames_[1] + "/bar", "Goodbye World!");
  375. source_tree_.MapPath("", dirnames_[0]);
  376. source_tree_.MapPath("", dirnames_[1]);
  377. ExpectFileContents("foo", "Hello World!");
  378. ExpectFileContents("bar", "Goodbye World!");
  379. ExpectFileNotFound("baz");
  380. }
  381. TEST_F(DiskSourceTreeTest, OrderingTrumpsSpecificity) {
  382. // Test that directories are always searched in order, even when a latter
  383. // directory is more-specific than a former one.
  384. // Create the "bar" directory so we can put a file in it.
  385. ASSERT_TRUE(File::CreateDir((dirnames_[0] + "/bar").c_str(),
  386. DEFAULT_FILE_MODE));
  387. // Add files and map paths.
  388. AddFile(dirnames_[0] + "/bar/foo", "Hello World!");
  389. AddFile(dirnames_[1] + "/foo", "This file should be hidden.");
  390. source_tree_.MapPath("", dirnames_[0]);
  391. source_tree_.MapPath("bar", dirnames_[1]);
  392. // Check.
  393. ExpectFileContents("bar/foo", "Hello World!");
  394. }
  395. TEST_F(DiskSourceTreeTest, DiskFileToVirtualFile) {
  396. // Test DiskFileToVirtualFile.
  397. AddFile(dirnames_[0] + "/foo", "Hello World!");
  398. AddFile(dirnames_[1] + "/foo", "This file should be hidden.");
  399. source_tree_.MapPath("bar", dirnames_[0]);
  400. source_tree_.MapPath("bar", dirnames_[1]);
  401. string virtual_file;
  402. string shadowing_disk_file;
  403. EXPECT_EQ(DiskSourceTree::NO_MAPPING,
  404. source_tree_.DiskFileToVirtualFile(
  405. "/foo", &virtual_file, &shadowing_disk_file));
  406. EXPECT_EQ(DiskSourceTree::SHADOWED,
  407. source_tree_.DiskFileToVirtualFile(
  408. dirnames_[1] + "/foo", &virtual_file, &shadowing_disk_file));
  409. EXPECT_EQ("bar/foo", virtual_file);
  410. EXPECT_EQ(dirnames_[0] + "/foo", shadowing_disk_file);
  411. EXPECT_EQ(DiskSourceTree::CANNOT_OPEN,
  412. source_tree_.DiskFileToVirtualFile(
  413. dirnames_[1] + "/baz", &virtual_file, &shadowing_disk_file));
  414. EXPECT_EQ("bar/baz", virtual_file);
  415. EXPECT_EQ(DiskSourceTree::SUCCESS,
  416. source_tree_.DiskFileToVirtualFile(
  417. dirnames_[0] + "/foo", &virtual_file, &shadowing_disk_file));
  418. EXPECT_EQ("bar/foo", virtual_file);
  419. }
  420. TEST_F(DiskSourceTreeTest, DiskFileToVirtualFileCanonicalization) {
  421. // Test handling of "..", ".", etc. in DiskFileToVirtualFile().
  422. source_tree_.MapPath("dir1", "..");
  423. source_tree_.MapPath("dir2", "../../foo");
  424. source_tree_.MapPath("dir3", "./foo/bar/.");
  425. source_tree_.MapPath("dir4", ".");
  426. source_tree_.MapPath("", "/qux");
  427. source_tree_.MapPath("dir5", "/quux/");
  428. string virtual_file;
  429. string shadowing_disk_file;
  430. // "../.." should not be considered to be under "..".
  431. EXPECT_EQ(DiskSourceTree::NO_MAPPING,
  432. source_tree_.DiskFileToVirtualFile(
  433. "../../baz", &virtual_file, &shadowing_disk_file));
  434. // "/foo" is not mapped (it should not be misintepreted as being under ".").
  435. EXPECT_EQ(DiskSourceTree::NO_MAPPING,
  436. source_tree_.DiskFileToVirtualFile(
  437. "/foo", &virtual_file, &shadowing_disk_file));
  438. #ifdef WIN32
  439. // "C:\foo" is not mapped (it should not be misintepreted as being under ".").
  440. EXPECT_EQ(DiskSourceTree::NO_MAPPING,
  441. source_tree_.DiskFileToVirtualFile(
  442. "C:\\foo", &virtual_file, &shadowing_disk_file));
  443. #endif // WIN32
  444. // But "../baz" should be.
  445. EXPECT_EQ(DiskSourceTree::CANNOT_OPEN,
  446. source_tree_.DiskFileToVirtualFile(
  447. "../baz", &virtual_file, &shadowing_disk_file));
  448. EXPECT_EQ("dir1/baz", virtual_file);
  449. // "../../foo/baz" is under "../../foo".
  450. EXPECT_EQ(DiskSourceTree::CANNOT_OPEN,
  451. source_tree_.DiskFileToVirtualFile(
  452. "../../foo/baz", &virtual_file, &shadowing_disk_file));
  453. EXPECT_EQ("dir2/baz", virtual_file);
  454. // "foo/./bar/baz" is under "./foo/bar/.".
  455. EXPECT_EQ(DiskSourceTree::CANNOT_OPEN,
  456. source_tree_.DiskFileToVirtualFile(
  457. "foo/bar/baz", &virtual_file, &shadowing_disk_file));
  458. EXPECT_EQ("dir3/baz", virtual_file);
  459. // "bar" is under ".".
  460. EXPECT_EQ(DiskSourceTree::CANNOT_OPEN,
  461. source_tree_.DiskFileToVirtualFile(
  462. "bar", &virtual_file, &shadowing_disk_file));
  463. EXPECT_EQ("dir4/bar", virtual_file);
  464. // "/qux/baz" is under "/qux".
  465. EXPECT_EQ(DiskSourceTree::CANNOT_OPEN,
  466. source_tree_.DiskFileToVirtualFile(
  467. "/qux/baz", &virtual_file, &shadowing_disk_file));
  468. EXPECT_EQ("baz", virtual_file);
  469. // "/quux/bar" is under "/quux".
  470. EXPECT_EQ(DiskSourceTree::CANNOT_OPEN,
  471. source_tree_.DiskFileToVirtualFile(
  472. "/quux/bar", &virtual_file, &shadowing_disk_file));
  473. EXPECT_EQ("dir5/bar", virtual_file);
  474. }
  475. TEST_F(DiskSourceTreeTest, VirtualFileToDiskFile) {
  476. // Test VirtualFileToDiskFile.
  477. AddFile(dirnames_[0] + "/foo", "Hello World!");
  478. AddFile(dirnames_[1] + "/foo", "This file should be hidden.");
  479. AddFile(dirnames_[1] + "/quux", "This file should not be hidden.");
  480. source_tree_.MapPath("bar", dirnames_[0]);
  481. source_tree_.MapPath("bar", dirnames_[1]);
  482. // Existent files, shadowed and non-shadowed case.
  483. string disk_file;
  484. EXPECT_TRUE(source_tree_.VirtualFileToDiskFile("bar/foo", &disk_file));
  485. EXPECT_EQ(dirnames_[0] + "/foo", disk_file);
  486. EXPECT_TRUE(source_tree_.VirtualFileToDiskFile("bar/quux", &disk_file));
  487. EXPECT_EQ(dirnames_[1] + "/quux", disk_file);
  488. // Nonexistent file in existent directory and vice versa.
  489. string not_touched = "not touched";
  490. EXPECT_FALSE(source_tree_.VirtualFileToDiskFile("bar/baz", &not_touched));
  491. EXPECT_EQ("not touched", not_touched);
  492. EXPECT_FALSE(source_tree_.VirtualFileToDiskFile("baz/foo", &not_touched));
  493. EXPECT_EQ("not touched", not_touched);
  494. // Accept NULL as output parameter.
  495. EXPECT_TRUE(source_tree_.VirtualFileToDiskFile("bar/foo", NULL));
  496. EXPECT_FALSE(source_tree_.VirtualFileToDiskFile("baz/foo", NULL));
  497. }
  498. } // namespace
  499. } // namespace compiler
  500. } // namespace protobuf
  501. } // namespace google