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