temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 1 | // Protocol Buffers - Google's data interchange format |
kenton@google.com | 24bf56f | 2008-09-24 20:31:01 +0000 | [diff] [blame] | 2 | // Copyright 2008 Google Inc. All rights reserved. |
Feng Xiao | e428862 | 2014-10-01 16:26:23 -0700 | [diff] [blame] | 3 | // https://developers.google.com/protocol-buffers/ |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 4 | // |
kenton@google.com | 24bf56f | 2008-09-24 20:31:01 +0000 | [diff] [blame] | 5 | // Redistribution and use in source and binary forms, with or without |
| 6 | // modification, are permitted provided that the following conditions are |
| 7 | // met: |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 8 | // |
kenton@google.com | 24bf56f | 2008-09-24 20:31:01 +0000 | [diff] [blame] | 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. |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 18 | // |
kenton@google.com | 24bf56f | 2008-09-24 20:31:01 +0000 | [diff] [blame] | 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. |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 30 | |
| 31 | // Author: kenton@google.com (Kenton Varda) |
| 32 | // Based on original Protocol Buffers design by |
| 33 | // Sanjay Ghemawat, Jeff Dean, and others. |
| 34 | |
temporal | 779f61c | 2008-08-13 03:15:00 +0000 | [diff] [blame] | 35 | #include <sys/types.h> |
| 36 | #include <sys/stat.h> |
| 37 | #include <fcntl.h> |
| 38 | #ifdef _MSC_VER |
| 39 | #include <io.h> |
| 40 | #else |
| 41 | #include <unistd.h> |
| 42 | #endif |
jieluo@google.com | 4de8f55 | 2014-07-18 00:47:59 +0000 | [diff] [blame] | 43 | #include <memory> |
Feng Xiao | 6ef984a | 2014-11-10 17:34:54 -0800 | [diff] [blame] | 44 | #ifndef _SHARED_PTR_H |
| 45 | #include <google/protobuf/stubs/shared_ptr.h> |
| 46 | #endif |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 47 | #include <vector> |
| 48 | |
temporal | 779f61c | 2008-08-13 03:15:00 +0000 | [diff] [blame] | 49 | #include <google/protobuf/descriptor.pb.h> |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 50 | #include <google/protobuf/descriptor.h> |
| 51 | #include <google/protobuf/io/zero_copy_stream.h> |
| 52 | #include <google/protobuf/compiler/command_line_interface.h> |
| 53 | #include <google/protobuf/compiler/code_generator.h> |
Feng Xiao | 6ef984a | 2014-11-10 17:34:54 -0800 | [diff] [blame] | 54 | #include <google/protobuf/testing/file.h> |
kenton@google.com | fccb146 | 2009-12-18 02:11:36 +0000 | [diff] [blame] | 55 | #include <google/protobuf/compiler/mock_code_generator.h> |
liujisi@google.com | 57014ff | 2010-12-21 05:56:35 +0000 | [diff] [blame] | 56 | #include <google/protobuf/compiler/subprocess.h> |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 57 | #include <google/protobuf/io/printer.h> |
temporal | 779f61c | 2008-08-13 03:15:00 +0000 | [diff] [blame] | 58 | #include <google/protobuf/unittest.pb.h> |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 59 | #include <google/protobuf/testing/file.h> |
| 60 | #include <google/protobuf/stubs/strutil.h> |
kenton@google.com | fccb146 | 2009-12-18 02:11:36 +0000 | [diff] [blame] | 61 | #include <google/protobuf/stubs/substitute.h> |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 62 | |
| 63 | #include <google/protobuf/testing/googletest.h> |
| 64 | #include <gtest/gtest.h> |
| 65 | |
Feng Xiao | 6ef984a | 2014-11-10 17:34:54 -0800 | [diff] [blame] | 66 | |
Jisi Liu | 7a00a1e | 2015-02-21 17:28:51 -0800 | [diff] [blame] | 67 | // Disable the whole test when we use tcmalloc for "draconian" heap checks, in |
| 68 | // which case tcmalloc will print warnings that fail the plugin tests. |
| 69 | #if !GOOGLE_PROTOBUF_HEAP_CHECK_DRACONIAN |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 70 | namespace google { |
| 71 | namespace protobuf { |
| 72 | namespace compiler { |
| 73 | |
temporal | 779f61c | 2008-08-13 03:15:00 +0000 | [diff] [blame] | 74 | #if defined(_WIN32) |
| 75 | #ifndef STDIN_FILENO |
| 76 | #define STDIN_FILENO 0 |
| 77 | #endif |
| 78 | #ifndef STDOUT_FILENO |
| 79 | #define STDOUT_FILENO 1 |
| 80 | #endif |
kenton@google.com | c0ee4d2 | 2009-12-22 02:05:33 +0000 | [diff] [blame] | 81 | #ifndef F_OK |
| 82 | #define F_OK 00 // not defined by MSVC for whatever reason |
| 83 | #endif |
temporal | 779f61c | 2008-08-13 03:15:00 +0000 | [diff] [blame] | 84 | #endif |
| 85 | |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 86 | namespace { |
| 87 | |
Feng Xiao | 6ef984a | 2014-11-10 17:34:54 -0800 | [diff] [blame] | 88 | bool FileExists(const string& path) { |
| 89 | return File::Exists(path); |
| 90 | } |
| 91 | |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 92 | class CommandLineInterfaceTest : public testing::Test { |
| 93 | protected: |
| 94 | virtual void SetUp(); |
| 95 | virtual void TearDown(); |
| 96 | |
| 97 | // Runs the CommandLineInterface with the given command line. The |
| 98 | // command is automatically split on spaces, and the string "$tmpdir" |
| 99 | // is replaced with TestTempDir(). |
jieluo@google.com | 8d6f04a | 2014-08-06 20:49:30 +0000 | [diff] [blame] | 100 | void Run(const string& command); |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 101 | |
| 102 | // ----------------------------------------------------------------- |
| 103 | // Methods to set up the test (called before Run()). |
| 104 | |
temporal | cc93043 | 2008-07-21 20:28:30 +0000 | [diff] [blame] | 105 | class NullCodeGenerator; |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 106 | |
kenton@google.com | fccb146 | 2009-12-18 02:11:36 +0000 | [diff] [blame] | 107 | // Normally plugins are allowed for all tests. Call this to explicitly |
| 108 | // disable them. |
| 109 | void DisallowPlugins() { disallow_plugins_ = true; } |
temporal | cc93043 | 2008-07-21 20:28:30 +0000 | [diff] [blame] | 110 | |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 111 | // Create a temp file within temp_directory_ with the given name. |
| 112 | // The containing directory is also created if necessary. |
| 113 | void CreateTempFile(const string& name, const string& contents); |
| 114 | |
kenton@google.com | fccb146 | 2009-12-18 02:11:36 +0000 | [diff] [blame] | 115 | // Create a subdirectory within temp_directory_. |
| 116 | void CreateTempDir(const string& name); |
| 117 | |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 118 | void SetInputsAreProtoPathRelative(bool enable) { |
| 119 | cli_.SetInputsAreProtoPathRelative(enable); |
| 120 | } |
| 121 | |
| 122 | // ----------------------------------------------------------------- |
| 123 | // Methods to check the test results (called after Run()). |
| 124 | |
| 125 | // Checks that no text was written to stderr during Run(), and Run() |
| 126 | // returned 0. |
| 127 | void ExpectNoErrors(); |
| 128 | |
| 129 | // Checks that Run() returned non-zero and the stderr output is exactly |
| 130 | // the text given. expected_test may contain references to "$tmpdir", |
| 131 | // which will be replaced by the temporary directory path. |
| 132 | void ExpectErrorText(const string& expected_text); |
| 133 | |
| 134 | // Checks that Run() returned non-zero and the stderr contains the given |
| 135 | // substring. |
| 136 | void ExpectErrorSubstring(const string& expected_substring); |
| 137 | |
xiaofeng@google.com | b55a20f | 2012-09-22 02:40:50 +0000 | [diff] [blame] | 138 | // Like ExpectErrorSubstring, but checks that Run() returned zero. |
| 139 | void ExpectErrorSubstringWithZeroReturnCode( |
| 140 | const string& expected_substring); |
| 141 | |
jieluo@google.com | 4de8f55 | 2014-07-18 00:47:59 +0000 | [diff] [blame] | 142 | // Checks that the captured stdout is the same as the expected_text. |
| 143 | void ExpectCapturedStdout(const string& expected_text); |
| 144 | |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 145 | // Returns true if ExpectErrorSubstring(expected_substring) would pass, but |
| 146 | // does not fail otherwise. |
| 147 | bool HasAlternateErrorSubstring(const string& expected_substring); |
| 148 | |
| 149 | // Checks that MockCodeGenerator::Generate() was called in the given |
kenton@google.com | fccb146 | 2009-12-18 02:11:36 +0000 | [diff] [blame] | 150 | // context (or the generator in test_plugin.cc, which produces the same |
| 151 | // output). That is, this tests if the generator with the given name |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 152 | // was called with the given parameter and proto file and produced the |
| 153 | // given output file. This is checked by reading the output file and |
| 154 | // checking that it contains the content that MockCodeGenerator would |
| 155 | // generate given these inputs. message_name is the name of the first |
| 156 | // message that appeared in the proto file; this is just to make extra |
| 157 | // sure that the correct file was parsed. |
| 158 | void ExpectGenerated(const string& generator_name, |
| 159 | const string& parameter, |
| 160 | const string& proto_name, |
kenton@google.com | fccb146 | 2009-12-18 02:11:36 +0000 | [diff] [blame] | 161 | const string& message_name); |
| 162 | void ExpectGenerated(const string& generator_name, |
| 163 | const string& parameter, |
| 164 | const string& proto_name, |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 165 | const string& message_name, |
kenton@google.com | fccb146 | 2009-12-18 02:11:36 +0000 | [diff] [blame] | 166 | const string& output_directory); |
liujisi@google.com | 33165fe | 2010-11-02 13:14:58 +0000 | [diff] [blame] | 167 | void ExpectGeneratedWithMultipleInputs(const string& generator_name, |
| 168 | const string& all_proto_names, |
| 169 | const string& proto_name, |
| 170 | const string& message_name); |
kenton@google.com | fccb146 | 2009-12-18 02:11:36 +0000 | [diff] [blame] | 171 | void ExpectGeneratedWithInsertions(const string& generator_name, |
| 172 | const string& parameter, |
| 173 | const string& insertions, |
| 174 | const string& proto_name, |
| 175 | const string& message_name); |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 176 | |
kenton@google.com | 91218af | 2009-12-18 07:20:43 +0000 | [diff] [blame] | 177 | void ExpectNullCodeGeneratorCalled(const string& parameter); |
| 178 | |
temporal | 779f61c | 2008-08-13 03:15:00 +0000 | [diff] [blame] | 179 | void ReadDescriptorSet(const string& filename, |
| 180 | FileDescriptorSet* descriptor_set); |
| 181 | |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 182 | private: |
| 183 | // The object we are testing. |
| 184 | CommandLineInterface cli_; |
| 185 | |
kenton@google.com | fccb146 | 2009-12-18 02:11:36 +0000 | [diff] [blame] | 186 | // Was DisallowPlugins() called? |
| 187 | bool disallow_plugins_; |
| 188 | |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 189 | // We create a directory within TestTempDir() in order to add extra |
| 190 | // protection against accidentally deleting user files (since we recursively |
| 191 | // delete this directory during the test). This is the full path of that |
| 192 | // directory. |
| 193 | string temp_directory_; |
| 194 | |
| 195 | // The result of Run(). |
| 196 | int return_code_; |
| 197 | |
| 198 | // The captured stderr output. |
| 199 | string error_text_; |
| 200 | |
jieluo@google.com | 4de8f55 | 2014-07-18 00:47:59 +0000 | [diff] [blame] | 201 | // The captured stdout. |
| 202 | string captured_stdout_; |
| 203 | |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 204 | // Pointers which need to be deleted later. |
temporal | cc93043 | 2008-07-21 20:28:30 +0000 | [diff] [blame] | 205 | vector<CodeGenerator*> mock_generators_to_delete_; |
kenton@google.com | 91218af | 2009-12-18 07:20:43 +0000 | [diff] [blame] | 206 | |
| 207 | NullCodeGenerator* null_generator_; |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 208 | }; |
| 209 | |
temporal | cc93043 | 2008-07-21 20:28:30 +0000 | [diff] [blame] | 210 | class CommandLineInterfaceTest::NullCodeGenerator : public CodeGenerator { |
| 211 | public: |
| 212 | NullCodeGenerator() : called_(false) {} |
| 213 | ~NullCodeGenerator() {} |
| 214 | |
| 215 | mutable bool called_; |
| 216 | mutable string parameter_; |
| 217 | |
| 218 | // implements CodeGenerator ---------------------------------------- |
| 219 | bool Generate(const FileDescriptor* file, |
| 220 | const string& parameter, |
liujisi@google.com | 33165fe | 2010-11-02 13:14:58 +0000 | [diff] [blame] | 221 | GeneratorContext* context, |
temporal | cc93043 | 2008-07-21 20:28:30 +0000 | [diff] [blame] | 222 | string* error) const { |
| 223 | called_ = true; |
| 224 | parameter_ = parameter; |
| 225 | return true; |
| 226 | } |
| 227 | }; |
| 228 | |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 229 | // =================================================================== |
| 230 | |
| 231 | void CommandLineInterfaceTest::SetUp() { |
| 232 | // Most of these tests were written before this option was added, so we |
| 233 | // run with the option on (which used to be the only way) except in certain |
| 234 | // tests where we turn it off. |
| 235 | cli_.SetInputsAreProtoPathRelative(true); |
| 236 | |
| 237 | temp_directory_ = TestTempDir() + "/proto2_cli_test_temp"; |
| 238 | |
| 239 | // If the temp directory already exists, it must be left over from a |
| 240 | // previous run. Delete it. |
Feng Xiao | 6ef984a | 2014-11-10 17:34:54 -0800 | [diff] [blame] | 241 | if (FileExists(temp_directory_)) { |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 242 | File::DeleteRecursively(temp_directory_, NULL, NULL); |
| 243 | } |
| 244 | |
| 245 | // Create the temp directory. |
jieluo@google.com | 4de8f55 | 2014-07-18 00:47:59 +0000 | [diff] [blame] | 246 | GOOGLE_CHECK_OK(File::CreateDir(temp_directory_, 0777)); |
kenton@google.com | fccb146 | 2009-12-18 02:11:36 +0000 | [diff] [blame] | 247 | |
| 248 | // Register generators. |
| 249 | CodeGenerator* generator = new MockCodeGenerator("test_generator"); |
| 250 | mock_generators_to_delete_.push_back(generator); |
xiaofeng@google.com | b55a20f | 2012-09-22 02:40:50 +0000 | [diff] [blame] | 251 | cli_.RegisterGenerator("--test_out", "--test_opt", generator, "Test output."); |
kenton@google.com | fccb146 | 2009-12-18 02:11:36 +0000 | [diff] [blame] | 252 | cli_.RegisterGenerator("-t", generator, "Test output."); |
| 253 | |
| 254 | generator = new MockCodeGenerator("alt_generator"); |
| 255 | mock_generators_to_delete_.push_back(generator); |
| 256 | cli_.RegisterGenerator("--alt_out", generator, "Alt output."); |
| 257 | |
kenton@google.com | 91218af | 2009-12-18 07:20:43 +0000 | [diff] [blame] | 258 | generator = null_generator_ = new NullCodeGenerator(); |
kenton@google.com | fccb146 | 2009-12-18 02:11:36 +0000 | [diff] [blame] | 259 | mock_generators_to_delete_.push_back(generator); |
| 260 | cli_.RegisterGenerator("--null_out", generator, "Null output."); |
| 261 | |
| 262 | disallow_plugins_ = false; |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 263 | } |
| 264 | |
| 265 | void CommandLineInterfaceTest::TearDown() { |
| 266 | // Delete the temp directory. |
Feng Xiao | f157a56 | 2014-11-14 11:50:31 -0800 | [diff] [blame] | 267 | if (FileExists(temp_directory_)) { |
Feng Xiao | baca1a8 | 2014-11-07 14:09:18 -0500 | [diff] [blame] | 268 | File::DeleteRecursively(temp_directory_, NULL, NULL); |
| 269 | } |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 270 | |
| 271 | // Delete all the MockCodeGenerators. |
| 272 | for (int i = 0; i < mock_generators_to_delete_.size(); i++) { |
| 273 | delete mock_generators_to_delete_[i]; |
| 274 | } |
| 275 | mock_generators_to_delete_.clear(); |
| 276 | } |
| 277 | |
jieluo@google.com | 8d6f04a | 2014-08-06 20:49:30 +0000 | [diff] [blame] | 278 | void CommandLineInterfaceTest::Run(const string& command) { |
jieluo@google.com | 4de8f55 | 2014-07-18 00:47:59 +0000 | [diff] [blame] | 279 | vector<string> args = Split(command, " ", true); |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 280 | |
kenton@google.com | fccb146 | 2009-12-18 02:11:36 +0000 | [diff] [blame] | 281 | if (!disallow_plugins_) { |
| 282 | cli_.AllowPlugins("prefix-"); |
kenton@google.com | c0ee4d2 | 2009-12-22 02:05:33 +0000 | [diff] [blame] | 283 | const char* possible_paths[] = { |
| 284 | // When building with shared libraries, libtool hides the real executable |
| 285 | // in .libs and puts a fake wrapper in the current directory. |
| 286 | // Unfortunately, due to an apparent bug on Cygwin/MinGW, if one program |
| 287 | // wrapped in this way (e.g. protobuf-tests.exe) tries to execute another |
| 288 | // program wrapped in this way (e.g. test_plugin.exe), the latter fails |
| 289 | // with error code 127 and no explanation message. Presumably the problem |
| 290 | // is that the wrapper for protobuf-tests.exe set some environment |
| 291 | // variables that confuse the wrapper for test_plugin.exe. Luckily, it |
| 292 | // turns out that if we simply invoke the wrapped test_plugin.exe |
| 293 | // directly, it works -- I guess the environment variables set by the |
| 294 | // protobuf-tests.exe wrapper happen to be correct for it too. So we do |
| 295 | // that. |
| 296 | ".libs/test_plugin.exe", // Win32 w/autotool (Cygwin / MinGW) |
| 297 | "test_plugin.exe", // Other Win32 (MSVC) |
| 298 | "test_plugin", // Unix |
| 299 | }; |
| 300 | |
| 301 | string plugin_path; |
| 302 | |
| 303 | for (int i = 0; i < GOOGLE_ARRAYSIZE(possible_paths); i++) { |
| 304 | if (access(possible_paths[i], F_OK) == 0) { |
| 305 | plugin_path = possible_paths[i]; |
| 306 | break; |
| 307 | } |
| 308 | } |
| 309 | |
| 310 | if (plugin_path.empty()) { |
| 311 | GOOGLE_LOG(ERROR) |
| 312 | << "Plugin executable not found. Plugin tests are likely to fail."; |
| 313 | } else { |
| 314 | args.push_back("--plugin=prefix-gen-plug=" + plugin_path); |
| 315 | } |
kenton@google.com | fccb146 | 2009-12-18 02:11:36 +0000 | [diff] [blame] | 316 | } |
| 317 | |
Feng Xiao | f157a56 | 2014-11-14 11:50:31 -0800 | [diff] [blame] | 318 | google::protobuf::scoped_array<const char * > argv(new const char* [args.size()]); |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 319 | |
| 320 | for (int i = 0; i < args.size(); i++) { |
| 321 | args[i] = StringReplace(args[i], "$tmpdir", temp_directory_, true); |
| 322 | argv[i] = args[i].c_str(); |
| 323 | } |
| 324 | |
jieluo@google.com | 8d6f04a | 2014-08-06 20:49:30 +0000 | [diff] [blame] | 325 | // TODO(jieluo): Cygwin doesn't work well if we try to capture stderr and |
| 326 | // stdout at the same time. Need to figure out why and add this capture back |
| 327 | // for Cygwin. |
| 328 | #if !defined(__CYGWIN__) |
| 329 | CaptureTestStdout(); |
| 330 | #endif |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 331 | CaptureTestStderr(); |
| 332 | |
| 333 | return_code_ = cli_.Run(args.size(), argv.get()); |
| 334 | |
| 335 | error_text_ = GetCapturedTestStderr(); |
jieluo@google.com | 8d6f04a | 2014-08-06 20:49:30 +0000 | [diff] [blame] | 336 | #if !defined(__CYGWIN__) |
| 337 | captured_stdout_ = GetCapturedTestStdout(); |
| 338 | #endif |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 339 | } |
| 340 | |
| 341 | // ------------------------------------------------------------------- |
| 342 | |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 343 | void CommandLineInterfaceTest::CreateTempFile( |
| 344 | const string& name, |
| 345 | const string& contents) { |
| 346 | // Create parent directory, if necessary. |
| 347 | string::size_type slash_pos = name.find_last_of('/'); |
| 348 | if (slash_pos != string::npos) { |
| 349 | string dir = name.substr(0, slash_pos); |
Feng Xiao | 6ef984a | 2014-11-10 17:34:54 -0800 | [diff] [blame] | 350 | if (!FileExists(temp_directory_ + "/" + dir)) { |
jieluo@google.com | 4de8f55 | 2014-07-18 00:47:59 +0000 | [diff] [blame] | 351 | GOOGLE_CHECK_OK(File::RecursivelyCreateDir(temp_directory_ + "/" + dir, |
| 352 | 0777)); |
| 353 | } |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 354 | } |
| 355 | |
| 356 | // Write file. |
| 357 | string full_name = temp_directory_ + "/" + name; |
jieluo@google.com | 4de8f55 | 2014-07-18 00:47:59 +0000 | [diff] [blame] | 358 | GOOGLE_CHECK_OK(File::SetContents(full_name, contents, true)); |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 359 | } |
| 360 | |
kenton@google.com | fccb146 | 2009-12-18 02:11:36 +0000 | [diff] [blame] | 361 | void CommandLineInterfaceTest::CreateTempDir(const string& name) { |
jieluo@google.com | 4de8f55 | 2014-07-18 00:47:59 +0000 | [diff] [blame] | 362 | GOOGLE_CHECK_OK(File::RecursivelyCreateDir(temp_directory_ + "/" + name, |
| 363 | 0777)); |
kenton@google.com | fccb146 | 2009-12-18 02:11:36 +0000 | [diff] [blame] | 364 | } |
| 365 | |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 366 | // ------------------------------------------------------------------- |
| 367 | |
| 368 | void CommandLineInterfaceTest::ExpectNoErrors() { |
| 369 | EXPECT_EQ(0, return_code_); |
| 370 | EXPECT_EQ("", error_text_); |
| 371 | } |
| 372 | |
| 373 | void CommandLineInterfaceTest::ExpectErrorText(const string& expected_text) { |
| 374 | EXPECT_NE(0, return_code_); |
| 375 | EXPECT_EQ(StringReplace(expected_text, "$tmpdir", temp_directory_, true), |
| 376 | error_text_); |
| 377 | } |
| 378 | |
| 379 | void CommandLineInterfaceTest::ExpectErrorSubstring( |
| 380 | const string& expected_substring) { |
| 381 | EXPECT_NE(0, return_code_); |
| 382 | EXPECT_PRED_FORMAT2(testing::IsSubstring, expected_substring, error_text_); |
| 383 | } |
| 384 | |
xiaofeng@google.com | b55a20f | 2012-09-22 02:40:50 +0000 | [diff] [blame] | 385 | void CommandLineInterfaceTest::ExpectErrorSubstringWithZeroReturnCode( |
| 386 | const string& expected_substring) { |
| 387 | EXPECT_EQ(0, return_code_); |
| 388 | EXPECT_PRED_FORMAT2(testing::IsSubstring, expected_substring, error_text_); |
| 389 | } |
| 390 | |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 391 | bool CommandLineInterfaceTest::HasAlternateErrorSubstring( |
| 392 | const string& expected_substring) { |
| 393 | EXPECT_NE(0, return_code_); |
| 394 | return error_text_.find(expected_substring) != string::npos; |
| 395 | } |
| 396 | |
| 397 | void CommandLineInterfaceTest::ExpectGenerated( |
| 398 | const string& generator_name, |
| 399 | const string& parameter, |
| 400 | const string& proto_name, |
kenton@google.com | fccb146 | 2009-12-18 02:11:36 +0000 | [diff] [blame] | 401 | const string& message_name) { |
| 402 | MockCodeGenerator::ExpectGenerated( |
liujisi@google.com | 33165fe | 2010-11-02 13:14:58 +0000 | [diff] [blame] | 403 | generator_name, parameter, "", proto_name, message_name, proto_name, |
| 404 | temp_directory_); |
kenton@google.com | fccb146 | 2009-12-18 02:11:36 +0000 | [diff] [blame] | 405 | } |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 406 | |
kenton@google.com | fccb146 | 2009-12-18 02:11:36 +0000 | [diff] [blame] | 407 | void CommandLineInterfaceTest::ExpectGenerated( |
| 408 | const string& generator_name, |
| 409 | const string& parameter, |
| 410 | const string& proto_name, |
| 411 | const string& message_name, |
| 412 | const string& output_directory) { |
| 413 | MockCodeGenerator::ExpectGenerated( |
liujisi@google.com | 33165fe | 2010-11-02 13:14:58 +0000 | [diff] [blame] | 414 | generator_name, parameter, "", proto_name, message_name, proto_name, |
kenton@google.com | fccb146 | 2009-12-18 02:11:36 +0000 | [diff] [blame] | 415 | temp_directory_ + "/" + output_directory); |
| 416 | } |
| 417 | |
liujisi@google.com | 33165fe | 2010-11-02 13:14:58 +0000 | [diff] [blame] | 418 | void CommandLineInterfaceTest::ExpectGeneratedWithMultipleInputs( |
| 419 | const string& generator_name, |
| 420 | const string& all_proto_names, |
| 421 | const string& proto_name, |
| 422 | const string& message_name) { |
| 423 | MockCodeGenerator::ExpectGenerated( |
| 424 | generator_name, "", "", proto_name, message_name, |
| 425 | all_proto_names, |
| 426 | temp_directory_); |
| 427 | } |
| 428 | |
kenton@google.com | fccb146 | 2009-12-18 02:11:36 +0000 | [diff] [blame] | 429 | void CommandLineInterfaceTest::ExpectGeneratedWithInsertions( |
| 430 | const string& generator_name, |
| 431 | const string& parameter, |
| 432 | const string& insertions, |
| 433 | const string& proto_name, |
| 434 | const string& message_name) { |
| 435 | MockCodeGenerator::ExpectGenerated( |
| 436 | generator_name, parameter, insertions, proto_name, message_name, |
liujisi@google.com | 33165fe | 2010-11-02 13:14:58 +0000 | [diff] [blame] | 437 | proto_name, temp_directory_); |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 438 | } |
| 439 | |
kenton@google.com | 91218af | 2009-12-18 07:20:43 +0000 | [diff] [blame] | 440 | void CommandLineInterfaceTest::ExpectNullCodeGeneratorCalled( |
| 441 | const string& parameter) { |
| 442 | EXPECT_TRUE(null_generator_->called_); |
| 443 | EXPECT_EQ(parameter, null_generator_->parameter_); |
| 444 | } |
| 445 | |
temporal | 779f61c | 2008-08-13 03:15:00 +0000 | [diff] [blame] | 446 | void CommandLineInterfaceTest::ReadDescriptorSet( |
| 447 | const string& filename, FileDescriptorSet* descriptor_set) { |
| 448 | string path = temp_directory_ + "/" + filename; |
| 449 | string file_contents; |
jieluo@google.com | 4de8f55 | 2014-07-18 00:47:59 +0000 | [diff] [blame] | 450 | GOOGLE_CHECK_OK(File::GetContents(path, &file_contents, true)); |
| 451 | |
temporal | 779f61c | 2008-08-13 03:15:00 +0000 | [diff] [blame] | 452 | if (!descriptor_set->ParseFromString(file_contents)) { |
| 453 | FAIL() << "Could not parse file contents: " << path; |
| 454 | } |
| 455 | } |
| 456 | |
jieluo@google.com | 4de8f55 | 2014-07-18 00:47:59 +0000 | [diff] [blame] | 457 | void CommandLineInterfaceTest::ExpectCapturedStdout( |
| 458 | const string& expected_text) { |
| 459 | EXPECT_EQ(expected_text, captured_stdout_); |
| 460 | } |
| 461 | |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 462 | // =================================================================== |
| 463 | |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 464 | TEST_F(CommandLineInterfaceTest, BasicOutput) { |
| 465 | // Test that the common case works. |
| 466 | |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 467 | CreateTempFile("foo.proto", |
| 468 | "syntax = \"proto2\";\n" |
| 469 | "message Foo {}\n"); |
| 470 | |
| 471 | Run("protocol_compiler --test_out=$tmpdir " |
| 472 | "--proto_path=$tmpdir foo.proto"); |
| 473 | |
| 474 | ExpectNoErrors(); |
kenton@google.com | fccb146 | 2009-12-18 02:11:36 +0000 | [diff] [blame] | 475 | ExpectGenerated("test_generator", "", "foo.proto", "Foo"); |
| 476 | } |
| 477 | |
| 478 | TEST_F(CommandLineInterfaceTest, BasicPlugin) { |
| 479 | // Test that basic plugins work. |
| 480 | |
| 481 | CreateTempFile("foo.proto", |
| 482 | "syntax = \"proto2\";\n" |
| 483 | "message Foo {}\n"); |
| 484 | |
| 485 | Run("protocol_compiler --plug_out=$tmpdir " |
| 486 | "--proto_path=$tmpdir foo.proto"); |
| 487 | |
| 488 | ExpectNoErrors(); |
| 489 | ExpectGenerated("test_plugin", "", "foo.proto", "Foo"); |
| 490 | } |
| 491 | |
| 492 | TEST_F(CommandLineInterfaceTest, GeneratorAndPlugin) { |
| 493 | // Invoke a generator and a plugin at the same time. |
| 494 | |
| 495 | CreateTempFile("foo.proto", |
| 496 | "syntax = \"proto2\";\n" |
| 497 | "message Foo {}\n"); |
| 498 | |
| 499 | Run("protocol_compiler --test_out=$tmpdir --plug_out=$tmpdir " |
| 500 | "--proto_path=$tmpdir foo.proto"); |
| 501 | |
| 502 | ExpectNoErrors(); |
| 503 | ExpectGenerated("test_generator", "", "foo.proto", "Foo"); |
| 504 | ExpectGenerated("test_plugin", "", "foo.proto", "Foo"); |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 505 | } |
| 506 | |
| 507 | TEST_F(CommandLineInterfaceTest, MultipleInputs) { |
| 508 | // Test parsing multiple input files. |
| 509 | |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 510 | CreateTempFile("foo.proto", |
| 511 | "syntax = \"proto2\";\n" |
| 512 | "message Foo {}\n"); |
| 513 | CreateTempFile("bar.proto", |
| 514 | "syntax = \"proto2\";\n" |
| 515 | "message Bar {}\n"); |
| 516 | |
kenton@google.com | fccb146 | 2009-12-18 02:11:36 +0000 | [diff] [blame] | 517 | Run("protocol_compiler --test_out=$tmpdir --plug_out=$tmpdir " |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 518 | "--proto_path=$tmpdir foo.proto bar.proto"); |
| 519 | |
| 520 | ExpectNoErrors(); |
liujisi@google.com | 33165fe | 2010-11-02 13:14:58 +0000 | [diff] [blame] | 521 | ExpectGeneratedWithMultipleInputs("test_generator", "foo.proto,bar.proto", |
| 522 | "foo.proto", "Foo"); |
| 523 | ExpectGeneratedWithMultipleInputs("test_generator", "foo.proto,bar.proto", |
| 524 | "bar.proto", "Bar"); |
| 525 | ExpectGeneratedWithMultipleInputs("test_plugin", "foo.proto,bar.proto", |
| 526 | "foo.proto", "Foo"); |
| 527 | ExpectGeneratedWithMultipleInputs("test_plugin", "foo.proto,bar.proto", |
| 528 | "bar.proto", "Bar"); |
| 529 | } |
| 530 | |
| 531 | TEST_F(CommandLineInterfaceTest, MultipleInputsWithImport) { |
| 532 | // Test parsing multiple input files with an import of a separate file. |
| 533 | |
| 534 | CreateTempFile("foo.proto", |
| 535 | "syntax = \"proto2\";\n" |
| 536 | "message Foo {}\n"); |
| 537 | CreateTempFile("bar.proto", |
| 538 | "syntax = \"proto2\";\n" |
| 539 | "import \"baz.proto\";\n" |
| 540 | "message Bar {\n" |
| 541 | " optional Baz a = 1;\n" |
| 542 | "}\n"); |
| 543 | CreateTempFile("baz.proto", |
| 544 | "syntax = \"proto2\";\n" |
| 545 | "message Baz {}\n"); |
| 546 | |
| 547 | Run("protocol_compiler --test_out=$tmpdir --plug_out=$tmpdir " |
| 548 | "--proto_path=$tmpdir foo.proto bar.proto"); |
| 549 | |
| 550 | ExpectNoErrors(); |
| 551 | ExpectGeneratedWithMultipleInputs("test_generator", "foo.proto,bar.proto", |
| 552 | "foo.proto", "Foo"); |
| 553 | ExpectGeneratedWithMultipleInputs("test_generator", "foo.proto,bar.proto", |
| 554 | "bar.proto", "Bar"); |
| 555 | ExpectGeneratedWithMultipleInputs("test_plugin", "foo.proto,bar.proto", |
| 556 | "foo.proto", "Foo"); |
| 557 | ExpectGeneratedWithMultipleInputs("test_plugin", "foo.proto,bar.proto", |
| 558 | "bar.proto", "Bar"); |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 559 | } |
| 560 | |
| 561 | TEST_F(CommandLineInterfaceTest, CreateDirectory) { |
| 562 | // Test that when we output to a sub-directory, it is created. |
| 563 | |
kenton@google.com | fccb146 | 2009-12-18 02:11:36 +0000 | [diff] [blame] | 564 | CreateTempFile("bar/baz/foo.proto", |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 565 | "syntax = \"proto2\";\n" |
| 566 | "message Foo {}\n"); |
kenton@google.com | fccb146 | 2009-12-18 02:11:36 +0000 | [diff] [blame] | 567 | CreateTempDir("out"); |
| 568 | CreateTempDir("plugout"); |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 569 | |
kenton@google.com | fccb146 | 2009-12-18 02:11:36 +0000 | [diff] [blame] | 570 | Run("protocol_compiler --test_out=$tmpdir/out --plug_out=$tmpdir/plugout " |
| 571 | "--proto_path=$tmpdir bar/baz/foo.proto"); |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 572 | |
| 573 | ExpectNoErrors(); |
kenton@google.com | fccb146 | 2009-12-18 02:11:36 +0000 | [diff] [blame] | 574 | ExpectGenerated("test_generator", "", "bar/baz/foo.proto", "Foo", "out"); |
| 575 | ExpectGenerated("test_plugin", "", "bar/baz/foo.proto", "Foo", "plugout"); |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 576 | } |
| 577 | |
| 578 | TEST_F(CommandLineInterfaceTest, GeneratorParameters) { |
| 579 | // Test that generator parameters are correctly parsed from the command line. |
| 580 | |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 581 | CreateTempFile("foo.proto", |
| 582 | "syntax = \"proto2\";\n" |
| 583 | "message Foo {}\n"); |
| 584 | |
| 585 | Run("protocol_compiler --test_out=TestParameter:$tmpdir " |
kenton@google.com | fccb146 | 2009-12-18 02:11:36 +0000 | [diff] [blame] | 586 | "--plug_out=TestPluginParameter:$tmpdir " |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 587 | "--proto_path=$tmpdir foo.proto"); |
| 588 | |
| 589 | ExpectNoErrors(); |
kenton@google.com | fccb146 | 2009-12-18 02:11:36 +0000 | [diff] [blame] | 590 | ExpectGenerated("test_generator", "TestParameter", "foo.proto", "Foo"); |
| 591 | ExpectGenerated("test_plugin", "TestPluginParameter", "foo.proto", "Foo"); |
| 592 | } |
| 593 | |
xiaofeng@google.com | b55a20f | 2012-09-22 02:40:50 +0000 | [diff] [blame] | 594 | TEST_F(CommandLineInterfaceTest, ExtraGeneratorParameters) { |
| 595 | // Test that generator parameters specified with the option flag are |
| 596 | // correctly passed to the code generator. |
| 597 | |
| 598 | CreateTempFile("foo.proto", |
| 599 | "syntax = \"proto2\";\n" |
| 600 | "message Foo {}\n"); |
| 601 | // Create the "a" and "b" sub-directories. |
| 602 | CreateTempDir("a"); |
| 603 | CreateTempDir("b"); |
| 604 | |
| 605 | Run("protocol_compiler " |
| 606 | "--test_opt=foo1 " |
| 607 | "--test_out=bar:$tmpdir/a " |
| 608 | "--test_opt=foo2 " |
| 609 | "--test_out=baz:$tmpdir/b " |
| 610 | "--test_opt=foo3 " |
| 611 | "--proto_path=$tmpdir foo.proto"); |
| 612 | |
| 613 | ExpectNoErrors(); |
| 614 | ExpectGenerated( |
| 615 | "test_generator", "bar,foo1,foo2,foo3", "foo.proto", "Foo", "a"); |
| 616 | ExpectGenerated( |
| 617 | "test_generator", "baz,foo1,foo2,foo3", "foo.proto", "Foo", "b"); |
| 618 | } |
| 619 | |
kenton@google.com | fccb146 | 2009-12-18 02:11:36 +0000 | [diff] [blame] | 620 | TEST_F(CommandLineInterfaceTest, Insert) { |
| 621 | // Test running a generator that inserts code into another's output. |
| 622 | |
| 623 | CreateTempFile("foo.proto", |
| 624 | "syntax = \"proto2\";\n" |
| 625 | "message Foo {}\n"); |
| 626 | |
| 627 | Run("protocol_compiler " |
| 628 | "--test_out=TestParameter:$tmpdir " |
| 629 | "--plug_out=TestPluginParameter:$tmpdir " |
| 630 | "--test_out=insert=test_generator,test_plugin:$tmpdir " |
| 631 | "--plug_out=insert=test_generator,test_plugin:$tmpdir " |
| 632 | "--proto_path=$tmpdir foo.proto"); |
| 633 | |
| 634 | ExpectNoErrors(); |
| 635 | ExpectGeneratedWithInsertions( |
| 636 | "test_generator", "TestParameter", "test_generator,test_plugin", |
| 637 | "foo.proto", "Foo"); |
| 638 | ExpectGeneratedWithInsertions( |
| 639 | "test_plugin", "TestPluginParameter", "test_generator,test_plugin", |
| 640 | "foo.proto", "Foo"); |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 641 | } |
| 642 | |
liujisi@google.com | 9b7f6c5 | 2010-12-08 03:45:27 +0000 | [diff] [blame] | 643 | #if defined(_WIN32) |
temporal | cc93043 | 2008-07-21 20:28:30 +0000 | [diff] [blame] | 644 | |
| 645 | TEST_F(CommandLineInterfaceTest, WindowsOutputPath) { |
| 646 | // Test that the output path can be a Windows-style path. |
| 647 | |
temporal | cc93043 | 2008-07-21 20:28:30 +0000 | [diff] [blame] | 648 | CreateTempFile("foo.proto", |
| 649 | "syntax = \"proto2\";\n"); |
| 650 | |
kenton@google.com | fccb146 | 2009-12-18 02:11:36 +0000 | [diff] [blame] | 651 | Run("protocol_compiler --null_out=C:\\ " |
temporal | cc93043 | 2008-07-21 20:28:30 +0000 | [diff] [blame] | 652 | "--proto_path=$tmpdir foo.proto"); |
| 653 | |
| 654 | ExpectNoErrors(); |
kenton@google.com | 91218af | 2009-12-18 07:20:43 +0000 | [diff] [blame] | 655 | ExpectNullCodeGeneratorCalled(""); |
temporal | cc93043 | 2008-07-21 20:28:30 +0000 | [diff] [blame] | 656 | } |
| 657 | |
| 658 | TEST_F(CommandLineInterfaceTest, WindowsOutputPathAndParameter) { |
| 659 | // Test that we can have a windows-style output path and a parameter. |
| 660 | |
temporal | cc93043 | 2008-07-21 20:28:30 +0000 | [diff] [blame] | 661 | CreateTempFile("foo.proto", |
| 662 | "syntax = \"proto2\";\n"); |
| 663 | |
kenton@google.com | fccb146 | 2009-12-18 02:11:36 +0000 | [diff] [blame] | 664 | Run("protocol_compiler --null_out=bar:C:\\ " |
temporal | cc93043 | 2008-07-21 20:28:30 +0000 | [diff] [blame] | 665 | "--proto_path=$tmpdir foo.proto"); |
| 666 | |
| 667 | ExpectNoErrors(); |
kenton@google.com | 91218af | 2009-12-18 07:20:43 +0000 | [diff] [blame] | 668 | ExpectNullCodeGeneratorCalled("bar"); |
temporal | cc93043 | 2008-07-21 20:28:30 +0000 | [diff] [blame] | 669 | } |
| 670 | |
kenton@google.com | ef3730c | 2009-04-28 00:49:36 +0000 | [diff] [blame] | 671 | TEST_F(CommandLineInterfaceTest, TrailingBackslash) { |
| 672 | // Test that the directories can end in backslashes. Some users claim this |
| 673 | // doesn't work on their system. |
| 674 | |
kenton@google.com | ef3730c | 2009-04-28 00:49:36 +0000 | [diff] [blame] | 675 | CreateTempFile("foo.proto", |
| 676 | "syntax = \"proto2\";\n" |
| 677 | "message Foo {}\n"); |
| 678 | |
| 679 | Run("protocol_compiler --test_out=$tmpdir\\ " |
| 680 | "--proto_path=$tmpdir\\ foo.proto"); |
| 681 | |
| 682 | ExpectNoErrors(); |
kenton@google.com | fccb146 | 2009-12-18 02:11:36 +0000 | [diff] [blame] | 683 | ExpectGenerated("test_generator", "", "foo.proto", "Foo"); |
kenton@google.com | ef3730c | 2009-04-28 00:49:36 +0000 | [diff] [blame] | 684 | } |
| 685 | |
temporal | cc93043 | 2008-07-21 20:28:30 +0000 | [diff] [blame] | 686 | #endif // defined(_WIN32) || defined(__CYGWIN__) |
| 687 | |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 688 | TEST_F(CommandLineInterfaceTest, PathLookup) { |
| 689 | // Test that specifying multiple directories in the proto search path works. |
| 690 | |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 691 | CreateTempFile("b/bar.proto", |
| 692 | "syntax = \"proto2\";\n" |
| 693 | "message Bar {}\n"); |
| 694 | CreateTempFile("a/foo.proto", |
| 695 | "syntax = \"proto2\";\n" |
| 696 | "import \"bar.proto\";\n" |
| 697 | "message Foo {\n" |
| 698 | " optional Bar a = 1;\n" |
| 699 | "}\n"); |
| 700 | CreateTempFile("b/foo.proto", "this should not be parsed\n"); |
| 701 | |
| 702 | Run("protocol_compiler --test_out=$tmpdir " |
| 703 | "--proto_path=$tmpdir/a --proto_path=$tmpdir/b foo.proto"); |
| 704 | |
| 705 | ExpectNoErrors(); |
kenton@google.com | fccb146 | 2009-12-18 02:11:36 +0000 | [diff] [blame] | 706 | ExpectGenerated("test_generator", "", "foo.proto", "Foo"); |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 707 | } |
| 708 | |
| 709 | TEST_F(CommandLineInterfaceTest, ColonDelimitedPath) { |
| 710 | // Same as PathLookup, but we provide the proto_path in a single flag. |
| 711 | |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 712 | CreateTempFile("b/bar.proto", |
| 713 | "syntax = \"proto2\";\n" |
| 714 | "message Bar {}\n"); |
| 715 | CreateTempFile("a/foo.proto", |
| 716 | "syntax = \"proto2\";\n" |
| 717 | "import \"bar.proto\";\n" |
| 718 | "message Foo {\n" |
| 719 | " optional Bar a = 1;\n" |
| 720 | "}\n"); |
| 721 | CreateTempFile("b/foo.proto", "this should not be parsed\n"); |
| 722 | |
| 723 | #undef PATH_SEPARATOR |
| 724 | #if defined(_WIN32) |
| 725 | #define PATH_SEPARATOR ";" |
| 726 | #else |
| 727 | #define PATH_SEPARATOR ":" |
| 728 | #endif |
| 729 | |
| 730 | Run("protocol_compiler --test_out=$tmpdir " |
Nobuaki Sukegawa | 8ba0e35 | 2014-11-30 19:42:51 +0900 | [diff] [blame] | 731 | "--proto_path=$tmpdir/a" PATH_SEPARATOR "$tmpdir/b foo.proto"); |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 732 | |
| 733 | #undef PATH_SEPARATOR |
| 734 | |
| 735 | ExpectNoErrors(); |
kenton@google.com | fccb146 | 2009-12-18 02:11:36 +0000 | [diff] [blame] | 736 | ExpectGenerated("test_generator", "", "foo.proto", "Foo"); |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 737 | } |
| 738 | |
| 739 | TEST_F(CommandLineInterfaceTest, NonRootMapping) { |
| 740 | // Test setting up a search path mapping a directory to a non-root location. |
| 741 | |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 742 | CreateTempFile("foo.proto", |
| 743 | "syntax = \"proto2\";\n" |
| 744 | "message Foo {}\n"); |
| 745 | |
| 746 | Run("protocol_compiler --test_out=$tmpdir " |
| 747 | "--proto_path=bar=$tmpdir bar/foo.proto"); |
| 748 | |
| 749 | ExpectNoErrors(); |
kenton@google.com | fccb146 | 2009-12-18 02:11:36 +0000 | [diff] [blame] | 750 | ExpectGenerated("test_generator", "", "bar/foo.proto", "Foo"); |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 751 | } |
| 752 | |
| 753 | TEST_F(CommandLineInterfaceTest, MultipleGenerators) { |
| 754 | // Test that we can have multiple generators and use both in one invocation, |
| 755 | // each with a different output directory. |
| 756 | |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 757 | CreateTempFile("foo.proto", |
| 758 | "syntax = \"proto2\";\n" |
| 759 | "message Foo {}\n"); |
| 760 | // Create the "a" and "b" sub-directories. |
kenton@google.com | fccb146 | 2009-12-18 02:11:36 +0000 | [diff] [blame] | 761 | CreateTempDir("a"); |
| 762 | CreateTempDir("b"); |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 763 | |
| 764 | Run("protocol_compiler " |
kenton@google.com | fccb146 | 2009-12-18 02:11:36 +0000 | [diff] [blame] | 765 | "--test_out=$tmpdir/a " |
| 766 | "--alt_out=$tmpdir/b " |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 767 | "--proto_path=$tmpdir foo.proto"); |
| 768 | |
| 769 | ExpectNoErrors(); |
kenton@google.com | fccb146 | 2009-12-18 02:11:36 +0000 | [diff] [blame] | 770 | ExpectGenerated("test_generator", "", "foo.proto", "Foo", "a"); |
| 771 | ExpectGenerated("alt_generator", "", "foo.proto", "Foo", "b"); |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 772 | } |
| 773 | |
| 774 | TEST_F(CommandLineInterfaceTest, DisallowServicesNoServices) { |
| 775 | // Test that --disallow_services doesn't cause a problem when there are no |
| 776 | // services. |
| 777 | |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 778 | CreateTempFile("foo.proto", |
| 779 | "syntax = \"proto2\";\n" |
| 780 | "message Foo {}\n"); |
| 781 | |
| 782 | Run("protocol_compiler --disallow_services --test_out=$tmpdir " |
| 783 | "--proto_path=$tmpdir foo.proto"); |
| 784 | |
| 785 | ExpectNoErrors(); |
kenton@google.com | fccb146 | 2009-12-18 02:11:36 +0000 | [diff] [blame] | 786 | ExpectGenerated("test_generator", "", "foo.proto", "Foo"); |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 787 | } |
| 788 | |
| 789 | TEST_F(CommandLineInterfaceTest, DisallowServicesHasService) { |
| 790 | // Test that --disallow_services produces an error when there are services. |
| 791 | |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 792 | CreateTempFile("foo.proto", |
| 793 | "syntax = \"proto2\";\n" |
| 794 | "message Foo {}\n" |
| 795 | "service Bar {}\n"); |
| 796 | |
| 797 | Run("protocol_compiler --disallow_services --test_out=$tmpdir " |
| 798 | "--proto_path=$tmpdir foo.proto"); |
| 799 | |
| 800 | ExpectErrorSubstring("foo.proto: This file contains services"); |
| 801 | } |
| 802 | |
| 803 | TEST_F(CommandLineInterfaceTest, AllowServicesHasService) { |
| 804 | // Test that services work fine as long as --disallow_services is not used. |
| 805 | |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 806 | CreateTempFile("foo.proto", |
| 807 | "syntax = \"proto2\";\n" |
| 808 | "message Foo {}\n" |
| 809 | "service Bar {}\n"); |
| 810 | |
| 811 | Run("protocol_compiler --test_out=$tmpdir " |
| 812 | "--proto_path=$tmpdir foo.proto"); |
| 813 | |
| 814 | ExpectNoErrors(); |
kenton@google.com | fccb146 | 2009-12-18 02:11:36 +0000 | [diff] [blame] | 815 | ExpectGenerated("test_generator", "", "foo.proto", "Foo"); |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 816 | } |
| 817 | |
| 818 | TEST_F(CommandLineInterfaceTest, CwdRelativeInputs) { |
| 819 | // Test that we can accept working-directory-relative input files. |
| 820 | |
| 821 | SetInputsAreProtoPathRelative(false); |
| 822 | |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 823 | CreateTempFile("foo.proto", |
| 824 | "syntax = \"proto2\";\n" |
| 825 | "message Foo {}\n"); |
| 826 | |
| 827 | Run("protocol_compiler --test_out=$tmpdir " |
| 828 | "--proto_path=$tmpdir $tmpdir/foo.proto"); |
| 829 | |
| 830 | ExpectNoErrors(); |
kenton@google.com | fccb146 | 2009-12-18 02:11:36 +0000 | [diff] [blame] | 831 | ExpectGenerated("test_generator", "", "foo.proto", "Foo"); |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 832 | } |
| 833 | |
temporal | 779f61c | 2008-08-13 03:15:00 +0000 | [diff] [blame] | 834 | TEST_F(CommandLineInterfaceTest, WriteDescriptorSet) { |
| 835 | CreateTempFile("foo.proto", |
| 836 | "syntax = \"proto2\";\n" |
| 837 | "message Foo {}\n"); |
| 838 | CreateTempFile("bar.proto", |
| 839 | "syntax = \"proto2\";\n" |
| 840 | "import \"foo.proto\";\n" |
| 841 | "message Bar {\n" |
| 842 | " optional Foo foo = 1;\n" |
| 843 | "}\n"); |
| 844 | |
| 845 | Run("protocol_compiler --descriptor_set_out=$tmpdir/descriptor_set " |
| 846 | "--proto_path=$tmpdir bar.proto"); |
| 847 | |
| 848 | ExpectNoErrors(); |
| 849 | |
| 850 | FileDescriptorSet descriptor_set; |
| 851 | ReadDescriptorSet("descriptor_set", &descriptor_set); |
| 852 | if (HasFatalFailure()) return; |
jieluo@google.com | 4de8f55 | 2014-07-18 00:47:59 +0000 | [diff] [blame] | 853 | EXPECT_EQ(1, descriptor_set.file_size()); |
temporal | 779f61c | 2008-08-13 03:15:00 +0000 | [diff] [blame] | 854 | EXPECT_EQ("bar.proto", descriptor_set.file(0).name()); |
xiaofeng@google.com | b55a20f | 2012-09-22 02:40:50 +0000 | [diff] [blame] | 855 | // Descriptor set should not have source code info. |
| 856 | EXPECT_FALSE(descriptor_set.file(0).has_source_code_info()); |
| 857 | } |
| 858 | |
| 859 | TEST_F(CommandLineInterfaceTest, WriteDescriptorSetWithSourceInfo) { |
| 860 | CreateTempFile("foo.proto", |
| 861 | "syntax = \"proto2\";\n" |
| 862 | "message Foo {}\n"); |
| 863 | CreateTempFile("bar.proto", |
| 864 | "syntax = \"proto2\";\n" |
| 865 | "import \"foo.proto\";\n" |
| 866 | "message Bar {\n" |
| 867 | " optional Foo foo = 1;\n" |
| 868 | "}\n"); |
| 869 | |
| 870 | Run("protocol_compiler --descriptor_set_out=$tmpdir/descriptor_set " |
| 871 | "--include_source_info --proto_path=$tmpdir bar.proto"); |
| 872 | |
| 873 | ExpectNoErrors(); |
| 874 | |
| 875 | FileDescriptorSet descriptor_set; |
| 876 | ReadDescriptorSet("descriptor_set", &descriptor_set); |
| 877 | if (HasFatalFailure()) return; |
jieluo@google.com | 4de8f55 | 2014-07-18 00:47:59 +0000 | [diff] [blame] | 878 | EXPECT_EQ(1, descriptor_set.file_size()); |
xiaofeng@google.com | b55a20f | 2012-09-22 02:40:50 +0000 | [diff] [blame] | 879 | EXPECT_EQ("bar.proto", descriptor_set.file(0).name()); |
| 880 | // Source code info included. |
| 881 | EXPECT_TRUE(descriptor_set.file(0).has_source_code_info()); |
temporal | 779f61c | 2008-08-13 03:15:00 +0000 | [diff] [blame] | 882 | } |
| 883 | |
| 884 | TEST_F(CommandLineInterfaceTest, WriteTransitiveDescriptorSet) { |
| 885 | CreateTempFile("foo.proto", |
| 886 | "syntax = \"proto2\";\n" |
| 887 | "message Foo {}\n"); |
| 888 | CreateTempFile("bar.proto", |
| 889 | "syntax = \"proto2\";\n" |
| 890 | "import \"foo.proto\";\n" |
| 891 | "message Bar {\n" |
| 892 | " optional Foo foo = 1;\n" |
| 893 | "}\n"); |
| 894 | |
| 895 | Run("protocol_compiler --descriptor_set_out=$tmpdir/descriptor_set " |
| 896 | "--include_imports --proto_path=$tmpdir bar.proto"); |
| 897 | |
| 898 | ExpectNoErrors(); |
| 899 | |
| 900 | FileDescriptorSet descriptor_set; |
| 901 | ReadDescriptorSet("descriptor_set", &descriptor_set); |
| 902 | if (HasFatalFailure()) return; |
jieluo@google.com | 4de8f55 | 2014-07-18 00:47:59 +0000 | [diff] [blame] | 903 | EXPECT_EQ(2, descriptor_set.file_size()); |
temporal | 779f61c | 2008-08-13 03:15:00 +0000 | [diff] [blame] | 904 | if (descriptor_set.file(0).name() == "bar.proto") { |
kenton@google.com | 7fb9ae9 | 2009-09-02 02:42:56 +0000 | [diff] [blame] | 905 | std::swap(descriptor_set.mutable_file()->mutable_data()[0], |
| 906 | descriptor_set.mutable_file()->mutable_data()[1]); |
temporal | 779f61c | 2008-08-13 03:15:00 +0000 | [diff] [blame] | 907 | } |
| 908 | EXPECT_EQ("foo.proto", descriptor_set.file(0).name()); |
| 909 | EXPECT_EQ("bar.proto", descriptor_set.file(1).name()); |
xiaofeng@google.com | b55a20f | 2012-09-22 02:40:50 +0000 | [diff] [blame] | 910 | // Descriptor set should not have source code info. |
| 911 | EXPECT_FALSE(descriptor_set.file(0).has_source_code_info()); |
| 912 | EXPECT_FALSE(descriptor_set.file(1).has_source_code_info()); |
| 913 | } |
| 914 | |
| 915 | TEST_F(CommandLineInterfaceTest, WriteTransitiveDescriptorSetWithSourceInfo) { |
| 916 | CreateTempFile("foo.proto", |
| 917 | "syntax = \"proto2\";\n" |
| 918 | "message Foo {}\n"); |
| 919 | CreateTempFile("bar.proto", |
| 920 | "syntax = \"proto2\";\n" |
| 921 | "import \"foo.proto\";\n" |
| 922 | "message Bar {\n" |
| 923 | " optional Foo foo = 1;\n" |
| 924 | "}\n"); |
| 925 | |
| 926 | Run("protocol_compiler --descriptor_set_out=$tmpdir/descriptor_set " |
| 927 | "--include_imports --include_source_info --proto_path=$tmpdir bar.proto"); |
| 928 | |
| 929 | ExpectNoErrors(); |
| 930 | |
| 931 | FileDescriptorSet descriptor_set; |
| 932 | ReadDescriptorSet("descriptor_set", &descriptor_set); |
| 933 | if (HasFatalFailure()) return; |
jieluo@google.com | 4de8f55 | 2014-07-18 00:47:59 +0000 | [diff] [blame] | 934 | EXPECT_EQ(2, descriptor_set.file_size()); |
xiaofeng@google.com | b55a20f | 2012-09-22 02:40:50 +0000 | [diff] [blame] | 935 | if (descriptor_set.file(0).name() == "bar.proto") { |
| 936 | std::swap(descriptor_set.mutable_file()->mutable_data()[0], |
| 937 | descriptor_set.mutable_file()->mutable_data()[1]); |
| 938 | } |
| 939 | EXPECT_EQ("foo.proto", descriptor_set.file(0).name()); |
| 940 | EXPECT_EQ("bar.proto", descriptor_set.file(1).name()); |
| 941 | // Source code info included. |
| 942 | EXPECT_TRUE(descriptor_set.file(0).has_source_code_info()); |
| 943 | EXPECT_TRUE(descriptor_set.file(1).has_source_code_info()); |
temporal | 779f61c | 2008-08-13 03:15:00 +0000 | [diff] [blame] | 944 | } |
| 945 | |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 946 | // ------------------------------------------------------------------- |
| 947 | |
| 948 | TEST_F(CommandLineInterfaceTest, ParseErrors) { |
| 949 | // Test that parse errors are reported. |
| 950 | |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 951 | CreateTempFile("foo.proto", |
| 952 | "syntax = \"proto2\";\n" |
| 953 | "badsyntax\n"); |
| 954 | |
| 955 | Run("protocol_compiler --test_out=$tmpdir " |
| 956 | "--proto_path=$tmpdir foo.proto"); |
| 957 | |
| 958 | ExpectErrorText( |
| 959 | "foo.proto:2:1: Expected top-level statement (e.g. \"message\").\n"); |
| 960 | } |
| 961 | |
| 962 | TEST_F(CommandLineInterfaceTest, ParseErrorsMultipleFiles) { |
| 963 | // Test that parse errors are reported from multiple files. |
| 964 | |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 965 | // We set up files such that foo.proto actually depends on bar.proto in |
| 966 | // two ways: Directly and through baz.proto. bar.proto's errors should |
| 967 | // only be reported once. |
| 968 | CreateTempFile("bar.proto", |
| 969 | "syntax = \"proto2\";\n" |
| 970 | "badsyntax\n"); |
| 971 | CreateTempFile("baz.proto", |
| 972 | "syntax = \"proto2\";\n" |
| 973 | "import \"bar.proto\";\n"); |
| 974 | CreateTempFile("foo.proto", |
| 975 | "syntax = \"proto2\";\n" |
| 976 | "import \"bar.proto\";\n" |
| 977 | "import \"baz.proto\";\n"); |
| 978 | |
| 979 | Run("protocol_compiler --test_out=$tmpdir " |
| 980 | "--proto_path=$tmpdir foo.proto"); |
| 981 | |
| 982 | ExpectErrorText( |
| 983 | "bar.proto:2:1: Expected top-level statement (e.g. \"message\").\n" |
| 984 | "baz.proto: Import \"bar.proto\" was not found or had errors.\n" |
| 985 | "foo.proto: Import \"bar.proto\" was not found or had errors.\n" |
| 986 | "foo.proto: Import \"baz.proto\" was not found or had errors.\n"); |
| 987 | } |
| 988 | |
| 989 | TEST_F(CommandLineInterfaceTest, InputNotFoundError) { |
| 990 | // Test what happens if the input file is not found. |
| 991 | |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 992 | Run("protocol_compiler --test_out=$tmpdir " |
| 993 | "--proto_path=$tmpdir foo.proto"); |
| 994 | |
| 995 | ExpectErrorText( |
| 996 | "foo.proto: File not found.\n"); |
| 997 | } |
| 998 | |
| 999 | TEST_F(CommandLineInterfaceTest, CwdRelativeInputNotFoundError) { |
| 1000 | // Test what happens when a working-directory-relative input file is not |
| 1001 | // found. |
| 1002 | |
| 1003 | SetInputsAreProtoPathRelative(false); |
| 1004 | |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 1005 | Run("protocol_compiler --test_out=$tmpdir " |
| 1006 | "--proto_path=$tmpdir $tmpdir/foo.proto"); |
| 1007 | |
| 1008 | ExpectErrorText( |
| 1009 | "$tmpdir/foo.proto: No such file or directory\n"); |
| 1010 | } |
| 1011 | |
| 1012 | TEST_F(CommandLineInterfaceTest, CwdRelativeInputNotMappedError) { |
| 1013 | // Test what happens when a working-directory-relative input file is not |
| 1014 | // mapped to a virtual path. |
| 1015 | |
| 1016 | SetInputsAreProtoPathRelative(false); |
| 1017 | |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 1018 | CreateTempFile("foo.proto", |
| 1019 | "syntax = \"proto2\";\n" |
| 1020 | "message Foo {}\n"); |
| 1021 | |
| 1022 | // Create a directory called "bar" so that we can point --proto_path at it. |
| 1023 | CreateTempFile("bar/dummy", ""); |
| 1024 | |
| 1025 | Run("protocol_compiler --test_out=$tmpdir " |
| 1026 | "--proto_path=$tmpdir/bar $tmpdir/foo.proto"); |
| 1027 | |
| 1028 | ExpectErrorText( |
| 1029 | "$tmpdir/foo.proto: File does not reside within any path " |
| 1030 | "specified using --proto_path (or -I). You must specify a " |
kenton@google.com | 477f799 | 2009-10-07 21:38:11 +0000 | [diff] [blame] | 1031 | "--proto_path which encompasses this file. Note that the " |
| 1032 | "proto_path must be an exact prefix of the .proto file " |
| 1033 | "names -- protoc is too dumb to figure out when two paths " |
| 1034 | "(e.g. absolute and relative) are equivalent (it's harder " |
| 1035 | "than you think).\n"); |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 1036 | } |
| 1037 | |
| 1038 | TEST_F(CommandLineInterfaceTest, CwdRelativeInputNotFoundAndNotMappedError) { |
| 1039 | // Check what happens if the input file is not found *and* is not mapped |
| 1040 | // in the proto_path. |
| 1041 | |
| 1042 | SetInputsAreProtoPathRelative(false); |
| 1043 | |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 1044 | // Create a directory called "bar" so that we can point --proto_path at it. |
| 1045 | CreateTempFile("bar/dummy", ""); |
| 1046 | |
| 1047 | Run("protocol_compiler --test_out=$tmpdir " |
| 1048 | "--proto_path=$tmpdir/bar $tmpdir/foo.proto"); |
| 1049 | |
| 1050 | ExpectErrorText( |
| 1051 | "$tmpdir/foo.proto: No such file or directory\n"); |
| 1052 | } |
| 1053 | |
| 1054 | TEST_F(CommandLineInterfaceTest, CwdRelativeInputShadowedError) { |
| 1055 | // Test what happens when a working-directory-relative input file is shadowed |
| 1056 | // by another file in the virtual path. |
| 1057 | |
| 1058 | SetInputsAreProtoPathRelative(false); |
| 1059 | |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 1060 | CreateTempFile("foo/foo.proto", |
| 1061 | "syntax = \"proto2\";\n" |
| 1062 | "message Foo {}\n"); |
| 1063 | CreateTempFile("bar/foo.proto", |
| 1064 | "syntax = \"proto2\";\n" |
| 1065 | "message Bar {}\n"); |
| 1066 | |
| 1067 | Run("protocol_compiler --test_out=$tmpdir " |
| 1068 | "--proto_path=$tmpdir/foo --proto_path=$tmpdir/bar " |
| 1069 | "$tmpdir/bar/foo.proto"); |
| 1070 | |
| 1071 | ExpectErrorText( |
| 1072 | "$tmpdir/bar/foo.proto: Input is shadowed in the --proto_path " |
| 1073 | "by \"$tmpdir/foo/foo.proto\". Either use the latter " |
| 1074 | "file as your input or reorder the --proto_path so that the " |
| 1075 | "former file's location comes first.\n"); |
| 1076 | } |
| 1077 | |
| 1078 | TEST_F(CommandLineInterfaceTest, ProtoPathNotFoundError) { |
| 1079 | // Test what happens if the input file is not found. |
| 1080 | |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 1081 | Run("protocol_compiler --test_out=$tmpdir " |
| 1082 | "--proto_path=$tmpdir/foo foo.proto"); |
| 1083 | |
| 1084 | ExpectErrorText( |
| 1085 | "$tmpdir/foo: warning: directory does not exist.\n" |
| 1086 | "foo.proto: File not found.\n"); |
| 1087 | } |
| 1088 | |
| 1089 | TEST_F(CommandLineInterfaceTest, MissingInputError) { |
| 1090 | // Test that we get an error if no inputs are given. |
| 1091 | |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 1092 | Run("protocol_compiler --test_out=$tmpdir " |
| 1093 | "--proto_path=$tmpdir"); |
| 1094 | |
| 1095 | ExpectErrorText("Missing input file.\n"); |
| 1096 | } |
| 1097 | |
| 1098 | TEST_F(CommandLineInterfaceTest, MissingOutputError) { |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 1099 | CreateTempFile("foo.proto", |
| 1100 | "syntax = \"proto2\";\n" |
| 1101 | "message Foo {}\n"); |
| 1102 | |
| 1103 | Run("protocol_compiler --proto_path=$tmpdir foo.proto"); |
| 1104 | |
| 1105 | ExpectErrorText("Missing output directives.\n"); |
| 1106 | } |
| 1107 | |
| 1108 | TEST_F(CommandLineInterfaceTest, OutputWriteError) { |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 1109 | CreateTempFile("foo.proto", |
| 1110 | "syntax = \"proto2\";\n" |
| 1111 | "message Foo {}\n"); |
| 1112 | |
kenton@google.com | fccb146 | 2009-12-18 02:11:36 +0000 | [diff] [blame] | 1113 | string output_file = |
| 1114 | MockCodeGenerator::GetOutputFileName("test_generator", "foo.proto"); |
| 1115 | |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 1116 | // Create a directory blocking our output location. |
kenton@google.com | fccb146 | 2009-12-18 02:11:36 +0000 | [diff] [blame] | 1117 | CreateTempDir(output_file); |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 1118 | |
| 1119 | Run("protocol_compiler --test_out=$tmpdir " |
| 1120 | "--proto_path=$tmpdir foo.proto"); |
| 1121 | |
kenton@google.com | 5f12164 | 2009-12-23 07:03:06 +0000 | [diff] [blame] | 1122 | // MockCodeGenerator no longer detects an error because we actually write to |
| 1123 | // an in-memory location first, then dump to disk at the end. This is no |
| 1124 | // big deal. |
| 1125 | // ExpectErrorSubstring("MockCodeGenerator detected write error."); |
kenton@google.com | fccb146 | 2009-12-18 02:11:36 +0000 | [diff] [blame] | 1126 | |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 1127 | #if defined(_WIN32) && !defined(__CYGWIN__) |
| 1128 | // Windows with MSVCRT.dll produces EPERM instead of EISDIR. |
kenton@google.com | fccb146 | 2009-12-18 02:11:36 +0000 | [diff] [blame] | 1129 | if (HasAlternateErrorSubstring(output_file + ": Permission denied")) { |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 1130 | return; |
| 1131 | } |
| 1132 | #endif |
| 1133 | |
kenton@google.com | fccb146 | 2009-12-18 02:11:36 +0000 | [diff] [blame] | 1134 | ExpectErrorSubstring(output_file + ": Is a directory"); |
| 1135 | } |
| 1136 | |
| 1137 | TEST_F(CommandLineInterfaceTest, PluginOutputWriteError) { |
| 1138 | CreateTempFile("foo.proto", |
| 1139 | "syntax = \"proto2\";\n" |
| 1140 | "message Foo {}\n"); |
| 1141 | |
| 1142 | string output_file = |
| 1143 | MockCodeGenerator::GetOutputFileName("test_plugin", "foo.proto"); |
| 1144 | |
| 1145 | // Create a directory blocking our output location. |
| 1146 | CreateTempDir(output_file); |
| 1147 | |
| 1148 | Run("protocol_compiler --plug_out=$tmpdir " |
| 1149 | "--proto_path=$tmpdir foo.proto"); |
| 1150 | |
| 1151 | #if defined(_WIN32) && !defined(__CYGWIN__) |
| 1152 | // Windows with MSVCRT.dll produces EPERM instead of EISDIR. |
| 1153 | if (HasAlternateErrorSubstring(output_file + ": Permission denied")) { |
| 1154 | return; |
| 1155 | } |
| 1156 | #endif |
| 1157 | |
| 1158 | ExpectErrorSubstring(output_file + ": Is a directory"); |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 1159 | } |
| 1160 | |
| 1161 | TEST_F(CommandLineInterfaceTest, OutputDirectoryNotFoundError) { |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 1162 | CreateTempFile("foo.proto", |
| 1163 | "syntax = \"proto2\";\n" |
| 1164 | "message Foo {}\n"); |
| 1165 | |
| 1166 | Run("protocol_compiler --test_out=$tmpdir/nosuchdir " |
| 1167 | "--proto_path=$tmpdir foo.proto"); |
| 1168 | |
kenton@google.com | fccb146 | 2009-12-18 02:11:36 +0000 | [diff] [blame] | 1169 | ExpectErrorSubstring("nosuchdir/: No such file or directory"); |
| 1170 | } |
| 1171 | |
| 1172 | TEST_F(CommandLineInterfaceTest, PluginOutputDirectoryNotFoundError) { |
| 1173 | CreateTempFile("foo.proto", |
| 1174 | "syntax = \"proto2\";\n" |
| 1175 | "message Foo {}\n"); |
| 1176 | |
| 1177 | Run("protocol_compiler --plug_out=$tmpdir/nosuchdir " |
| 1178 | "--proto_path=$tmpdir foo.proto"); |
| 1179 | |
| 1180 | ExpectErrorSubstring("nosuchdir/: No such file or directory"); |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 1181 | } |
| 1182 | |
| 1183 | TEST_F(CommandLineInterfaceTest, OutputDirectoryIsFileError) { |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 1184 | CreateTempFile("foo.proto", |
| 1185 | "syntax = \"proto2\";\n" |
| 1186 | "message Foo {}\n"); |
| 1187 | |
| 1188 | Run("protocol_compiler --test_out=$tmpdir/foo.proto " |
| 1189 | "--proto_path=$tmpdir foo.proto"); |
| 1190 | |
| 1191 | #if defined(_WIN32) && !defined(__CYGWIN__) |
| 1192 | // Windows with MSVCRT.dll produces EINVAL instead of ENOTDIR. |
| 1193 | if (HasAlternateErrorSubstring("foo.proto/: Invalid argument")) { |
| 1194 | return; |
| 1195 | } |
| 1196 | #endif |
| 1197 | |
| 1198 | ExpectErrorSubstring("foo.proto/: Not a directory"); |
| 1199 | } |
| 1200 | |
| 1201 | TEST_F(CommandLineInterfaceTest, GeneratorError) { |
kenton@google.com | fccb146 | 2009-12-18 02:11:36 +0000 | [diff] [blame] | 1202 | CreateTempFile("foo.proto", |
| 1203 | "syntax = \"proto2\";\n" |
| 1204 | "message MockCodeGenerator_Error {}\n"); |
| 1205 | |
| 1206 | Run("protocol_compiler --test_out=$tmpdir " |
| 1207 | "--proto_path=$tmpdir foo.proto"); |
| 1208 | |
| 1209 | ExpectErrorSubstring( |
| 1210 | "--test_out: foo.proto: Saw message type MockCodeGenerator_Error."); |
| 1211 | } |
| 1212 | |
| 1213 | TEST_F(CommandLineInterfaceTest, GeneratorPluginError) { |
| 1214 | // Test a generator plugin that returns an error. |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 1215 | |
| 1216 | CreateTempFile("foo.proto", |
| 1217 | "syntax = \"proto2\";\n" |
kenton@google.com | fccb146 | 2009-12-18 02:11:36 +0000 | [diff] [blame] | 1218 | "message MockCodeGenerator_Error {}\n"); |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 1219 | |
kenton@google.com | fccb146 | 2009-12-18 02:11:36 +0000 | [diff] [blame] | 1220 | Run("protocol_compiler --plug_out=TestParameter:$tmpdir " |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 1221 | "--proto_path=$tmpdir foo.proto"); |
| 1222 | |
kenton@google.com | fccb146 | 2009-12-18 02:11:36 +0000 | [diff] [blame] | 1223 | ExpectErrorSubstring( |
| 1224 | "--plug_out: foo.proto: Saw message type MockCodeGenerator_Error."); |
| 1225 | } |
| 1226 | |
| 1227 | TEST_F(CommandLineInterfaceTest, GeneratorPluginFail) { |
| 1228 | // Test a generator plugin that exits with an error code. |
| 1229 | |
| 1230 | CreateTempFile("foo.proto", |
| 1231 | "syntax = \"proto2\";\n" |
| 1232 | "message MockCodeGenerator_Exit {}\n"); |
| 1233 | |
| 1234 | Run("protocol_compiler --plug_out=TestParameter:$tmpdir " |
| 1235 | "--proto_path=$tmpdir foo.proto"); |
| 1236 | |
| 1237 | ExpectErrorSubstring("Saw message type MockCodeGenerator_Exit."); |
| 1238 | ExpectErrorSubstring( |
| 1239 | "--plug_out: prefix-gen-plug: Plugin failed with status code 123."); |
| 1240 | } |
| 1241 | |
| 1242 | TEST_F(CommandLineInterfaceTest, GeneratorPluginCrash) { |
| 1243 | // Test a generator plugin that crashes. |
| 1244 | |
| 1245 | CreateTempFile("foo.proto", |
| 1246 | "syntax = \"proto2\";\n" |
| 1247 | "message MockCodeGenerator_Abort {}\n"); |
| 1248 | |
| 1249 | Run("protocol_compiler --plug_out=TestParameter:$tmpdir " |
| 1250 | "--proto_path=$tmpdir foo.proto"); |
| 1251 | |
| 1252 | ExpectErrorSubstring("Saw message type MockCodeGenerator_Abort."); |
| 1253 | |
kenton@google.com | 684d45b | 2009-12-19 04:50:00 +0000 | [diff] [blame] | 1254 | #ifdef _WIN32 |
| 1255 | // Windows doesn't have signals. It looks like abort()ing causes the process |
| 1256 | // to exit with status code 3, but let's not depend on the exact number here. |
| 1257 | ExpectErrorSubstring( |
| 1258 | "--plug_out: prefix-gen-plug: Plugin failed with status code"); |
| 1259 | #else |
kenton@google.com | fccb146 | 2009-12-18 02:11:36 +0000 | [diff] [blame] | 1260 | // Don't depend on the exact signal number. |
| 1261 | ExpectErrorSubstring( |
| 1262 | "--plug_out: prefix-gen-plug: Plugin killed by signal"); |
kenton@google.com | 684d45b | 2009-12-19 04:50:00 +0000 | [diff] [blame] | 1263 | #endif |
kenton@google.com | fccb146 | 2009-12-18 02:11:36 +0000 | [diff] [blame] | 1264 | } |
| 1265 | |
xiaofeng@google.com | b55a20f | 2012-09-22 02:40:50 +0000 | [diff] [blame] | 1266 | TEST_F(CommandLineInterfaceTest, PluginReceivesSourceCodeInfo) { |
| 1267 | CreateTempFile("foo.proto", |
| 1268 | "syntax = \"proto2\";\n" |
| 1269 | "message MockCodeGenerator_HasSourceCodeInfo {}\n"); |
| 1270 | |
| 1271 | Run("protocol_compiler --plug_out=$tmpdir --proto_path=$tmpdir foo.proto"); |
| 1272 | |
| 1273 | ExpectErrorSubstring( |
| 1274 | "Saw message type MockCodeGenerator_HasSourceCodeInfo: 1."); |
| 1275 | } |
| 1276 | |
kenton@google.com | fccb146 | 2009-12-18 02:11:36 +0000 | [diff] [blame] | 1277 | TEST_F(CommandLineInterfaceTest, GeneratorPluginNotFound) { |
| 1278 | // Test what happens if the plugin isn't found. |
| 1279 | |
| 1280 | CreateTempFile("error.proto", |
| 1281 | "syntax = \"proto2\";\n" |
| 1282 | "message Foo {}\n"); |
| 1283 | |
| 1284 | Run("protocol_compiler --badplug_out=TestParameter:$tmpdir " |
| 1285 | "--plugin=prefix-gen-badplug=no_such_file " |
| 1286 | "--proto_path=$tmpdir error.proto"); |
| 1287 | |
kenton@google.com | 684d45b | 2009-12-19 04:50:00 +0000 | [diff] [blame] | 1288 | #ifdef _WIN32 |
liujisi@google.com | 57014ff | 2010-12-21 05:56:35 +0000 | [diff] [blame] | 1289 | ExpectErrorSubstring("--badplug_out: prefix-gen-badplug: " + |
| 1290 | Subprocess::Win32ErrorMessage(ERROR_FILE_NOT_FOUND)); |
kenton@google.com | 684d45b | 2009-12-19 04:50:00 +0000 | [diff] [blame] | 1291 | #else |
| 1292 | // Error written to stdout by child process after exec() fails. |
kenton@google.com | fccb146 | 2009-12-18 02:11:36 +0000 | [diff] [blame] | 1293 | ExpectErrorSubstring( |
| 1294 | "no_such_file: program not found or is not executable"); |
| 1295 | |
kenton@google.com | 684d45b | 2009-12-19 04:50:00 +0000 | [diff] [blame] | 1296 | // Error written by parent process when child fails. |
kenton@google.com | fccb146 | 2009-12-18 02:11:36 +0000 | [diff] [blame] | 1297 | ExpectErrorSubstring( |
| 1298 | "--badplug_out: prefix-gen-badplug: Plugin failed with status code 1."); |
kenton@google.com | 684d45b | 2009-12-19 04:50:00 +0000 | [diff] [blame] | 1299 | #endif |
kenton@google.com | fccb146 | 2009-12-18 02:11:36 +0000 | [diff] [blame] | 1300 | } |
| 1301 | |
| 1302 | TEST_F(CommandLineInterfaceTest, GeneratorPluginNotAllowed) { |
| 1303 | // Test what happens if plugins aren't allowed. |
| 1304 | |
| 1305 | CreateTempFile("error.proto", |
| 1306 | "syntax = \"proto2\";\n" |
| 1307 | "message Foo {}\n"); |
| 1308 | |
| 1309 | DisallowPlugins(); |
| 1310 | Run("protocol_compiler --plug_out=TestParameter:$tmpdir " |
| 1311 | "--proto_path=$tmpdir error.proto"); |
| 1312 | |
| 1313 | ExpectErrorSubstring("Unknown flag: --plug_out"); |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 1314 | } |
| 1315 | |
| 1316 | TEST_F(CommandLineInterfaceTest, HelpText) { |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 1317 | Run("test_exec_name --help"); |
| 1318 | |
xiaofeng@google.com | b55a20f | 2012-09-22 02:40:50 +0000 | [diff] [blame] | 1319 | ExpectErrorSubstringWithZeroReturnCode("Usage: test_exec_name "); |
| 1320 | ExpectErrorSubstringWithZeroReturnCode("--test_out=OUT_DIR"); |
| 1321 | ExpectErrorSubstringWithZeroReturnCode("Test output."); |
| 1322 | ExpectErrorSubstringWithZeroReturnCode("--alt_out=OUT_DIR"); |
| 1323 | ExpectErrorSubstringWithZeroReturnCode("Alt output."); |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 1324 | } |
| 1325 | |
kenton@google.com | f663b16 | 2009-04-15 19:50:54 +0000 | [diff] [blame] | 1326 | TEST_F(CommandLineInterfaceTest, GccFormatErrors) { |
| 1327 | // Test --error_format=gcc (which is the default, but we want to verify |
| 1328 | // that it can be set explicitly). |
| 1329 | |
kenton@google.com | f663b16 | 2009-04-15 19:50:54 +0000 | [diff] [blame] | 1330 | CreateTempFile("foo.proto", |
| 1331 | "syntax = \"proto2\";\n" |
| 1332 | "badsyntax\n"); |
| 1333 | |
| 1334 | Run("protocol_compiler --test_out=$tmpdir " |
| 1335 | "--proto_path=$tmpdir --error_format=gcc foo.proto"); |
| 1336 | |
| 1337 | ExpectErrorText( |
| 1338 | "foo.proto:2:1: Expected top-level statement (e.g. \"message\").\n"); |
| 1339 | } |
| 1340 | |
| 1341 | TEST_F(CommandLineInterfaceTest, MsvsFormatErrors) { |
| 1342 | // Test --error_format=msvs |
| 1343 | |
kenton@google.com | f663b16 | 2009-04-15 19:50:54 +0000 | [diff] [blame] | 1344 | CreateTempFile("foo.proto", |
| 1345 | "syntax = \"proto2\";\n" |
| 1346 | "badsyntax\n"); |
| 1347 | |
| 1348 | Run("protocol_compiler --test_out=$tmpdir " |
| 1349 | "--proto_path=$tmpdir --error_format=msvs foo.proto"); |
| 1350 | |
| 1351 | ExpectErrorText( |
kenton@google.com | 6793c1a | 2010-04-05 21:45:45 +0000 | [diff] [blame] | 1352 | "$tmpdir/foo.proto(2) : error in column=1: Expected top-level statement " |
kenton@google.com | f663b16 | 2009-04-15 19:50:54 +0000 | [diff] [blame] | 1353 | "(e.g. \"message\").\n"); |
| 1354 | } |
| 1355 | |
| 1356 | TEST_F(CommandLineInterfaceTest, InvalidErrorFormat) { |
| 1357 | // Test --error_format=msvs |
| 1358 | |
kenton@google.com | f663b16 | 2009-04-15 19:50:54 +0000 | [diff] [blame] | 1359 | CreateTempFile("foo.proto", |
| 1360 | "syntax = \"proto2\";\n" |
| 1361 | "badsyntax\n"); |
| 1362 | |
| 1363 | Run("protocol_compiler --test_out=$tmpdir " |
| 1364 | "--proto_path=$tmpdir --error_format=invalid foo.proto"); |
| 1365 | |
| 1366 | ExpectErrorText( |
| 1367 | "Unknown error format: invalid\n"); |
| 1368 | } |
| 1369 | |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 1370 | // ------------------------------------------------------------------- |
| 1371 | // Flag parsing tests |
| 1372 | |
| 1373 | TEST_F(CommandLineInterfaceTest, ParseSingleCharacterFlag) { |
| 1374 | // Test that a single-character flag works. |
| 1375 | |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 1376 | CreateTempFile("foo.proto", |
| 1377 | "syntax = \"proto2\";\n" |
| 1378 | "message Foo {}\n"); |
| 1379 | |
temporal | 779f61c | 2008-08-13 03:15:00 +0000 | [diff] [blame] | 1380 | Run("protocol_compiler -t$tmpdir " |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 1381 | "--proto_path=$tmpdir foo.proto"); |
| 1382 | |
| 1383 | ExpectNoErrors(); |
kenton@google.com | fccb146 | 2009-12-18 02:11:36 +0000 | [diff] [blame] | 1384 | ExpectGenerated("test_generator", "", "foo.proto", "Foo"); |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 1385 | } |
| 1386 | |
| 1387 | TEST_F(CommandLineInterfaceTest, ParseSpaceDelimitedValue) { |
| 1388 | // Test that separating the flag value with a space works. |
| 1389 | |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 1390 | CreateTempFile("foo.proto", |
| 1391 | "syntax = \"proto2\";\n" |
| 1392 | "message Foo {}\n"); |
| 1393 | |
| 1394 | Run("protocol_compiler --test_out $tmpdir " |
| 1395 | "--proto_path=$tmpdir foo.proto"); |
| 1396 | |
| 1397 | ExpectNoErrors(); |
kenton@google.com | fccb146 | 2009-12-18 02:11:36 +0000 | [diff] [blame] | 1398 | ExpectGenerated("test_generator", "", "foo.proto", "Foo"); |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 1399 | } |
| 1400 | |
| 1401 | TEST_F(CommandLineInterfaceTest, ParseSingleCharacterSpaceDelimitedValue) { |
| 1402 | // Test that separating the flag value with a space works for |
| 1403 | // single-character flags. |
| 1404 | |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 1405 | CreateTempFile("foo.proto", |
| 1406 | "syntax = \"proto2\";\n" |
| 1407 | "message Foo {}\n"); |
| 1408 | |
temporal | 779f61c | 2008-08-13 03:15:00 +0000 | [diff] [blame] | 1409 | Run("protocol_compiler -t $tmpdir " |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 1410 | "--proto_path=$tmpdir foo.proto"); |
| 1411 | |
| 1412 | ExpectNoErrors(); |
kenton@google.com | fccb146 | 2009-12-18 02:11:36 +0000 | [diff] [blame] | 1413 | ExpectGenerated("test_generator", "", "foo.proto", "Foo"); |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 1414 | } |
| 1415 | |
| 1416 | TEST_F(CommandLineInterfaceTest, MissingValueError) { |
| 1417 | // Test that we get an error if a flag is missing its value. |
| 1418 | |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 1419 | Run("protocol_compiler --test_out --proto_path=$tmpdir foo.proto"); |
| 1420 | |
| 1421 | ExpectErrorText("Missing value for flag: --test_out\n"); |
| 1422 | } |
| 1423 | |
| 1424 | TEST_F(CommandLineInterfaceTest, MissingValueAtEndError) { |
| 1425 | // Test that we get an error if the last argument is a flag requiring a |
| 1426 | // value. |
| 1427 | |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 1428 | Run("protocol_compiler --test_out"); |
| 1429 | |
| 1430 | ExpectErrorText("Missing value for flag: --test_out\n"); |
| 1431 | } |
| 1432 | |
jieluo@google.com | 4de8f55 | 2014-07-18 00:47:59 +0000 | [diff] [blame] | 1433 | TEST_F(CommandLineInterfaceTest, PrintFreeFieldNumbers) { |
| 1434 | CreateTempFile( |
| 1435 | "foo.proto", |
| 1436 | "syntax = \"proto2\";\n" |
| 1437 | "package foo;\n" |
| 1438 | "message Foo {\n" |
| 1439 | " optional int32 a = 2;\n" |
| 1440 | " optional string b = 4;\n" |
| 1441 | " optional string c = 5;\n" |
| 1442 | " optional int64 d = 8;\n" |
| 1443 | " optional double e = 10;\n" |
| 1444 | "}\n"); |
| 1445 | CreateTempFile( |
| 1446 | "bar.proto", |
| 1447 | "syntax = \"proto2\";\n" |
| 1448 | "message Bar {\n" |
| 1449 | " optional int32 a = 2;\n" |
| 1450 | " extensions 4 to 5;\n" |
| 1451 | " optional int64 d = 8;\n" |
| 1452 | " extensions 10;\n" |
| 1453 | "}\n"); |
| 1454 | CreateTempFile( |
| 1455 | "baz.proto", |
| 1456 | "syntax = \"proto2\";\n" |
| 1457 | "message Baz {\n" |
| 1458 | " optional int32 a = 2;\n" |
| 1459 | " optional int64 d = 8;\n" |
| 1460 | " extensions 15 to max;\n" // unordered. |
| 1461 | " extensions 13;\n" |
| 1462 | " extensions 10 to 12;\n" |
| 1463 | " extensions 5;\n" |
| 1464 | " extensions 4;\n" |
| 1465 | "}\n"); |
| 1466 | CreateTempFile( |
| 1467 | "quz.proto", |
| 1468 | "syntax = \"proto2\";\n" |
| 1469 | "message Quz {\n" |
| 1470 | " message Foo {}\n" // nested message |
| 1471 | " optional int32 a = 2;\n" |
| 1472 | " optional group C = 4 {\n" |
| 1473 | " optional int32 d = 5;\n" |
| 1474 | " }\n" |
| 1475 | " extensions 8 to 10;\n" |
| 1476 | " optional group E = 11 {\n" |
| 1477 | " optional int32 f = 9;\n" // explicitly reuse extension range 8-10 |
| 1478 | " optional group G = 15 {\n" // nested group |
| 1479 | " message Foo {}\n" // nested message inside nested group |
| 1480 | " }\n" |
| 1481 | " }\n" |
| 1482 | "}\n"); |
| 1483 | |
| 1484 | Run("protocol_compiler --print_free_field_numbers --proto_path=$tmpdir " |
jieluo@google.com | 8d6f04a | 2014-08-06 20:49:30 +0000 | [diff] [blame] | 1485 | "foo.proto bar.proto baz.proto quz.proto"); |
jieluo@google.com | 4de8f55 | 2014-07-18 00:47:59 +0000 | [diff] [blame] | 1486 | |
| 1487 | ExpectNoErrors(); |
jieluo@google.com | 8d6f04a | 2014-08-06 20:49:30 +0000 | [diff] [blame] | 1488 | |
| 1489 | // TODO(jieluo): Cygwin doesn't work well if we try to capture stderr and |
| 1490 | // stdout at the same time. Need to figure out why and add this test back |
| 1491 | // for Cygwin. |
| 1492 | #if !defined(__CYGWIN__) |
jieluo@google.com | 4de8f55 | 2014-07-18 00:47:59 +0000 | [diff] [blame] | 1493 | ExpectCapturedStdout( |
| 1494 | "foo.Foo free: 1 3 6-7 9 11-INF\n" |
| 1495 | "Bar free: 1 3 6-7 9 11-INF\n" |
| 1496 | "Baz free: 1 3 6-7 9 14\n" |
| 1497 | "Quz.Foo free: 1-INF\n" |
| 1498 | "Quz.E.G.Foo free: 1-INF\n" |
| 1499 | "Quz free: 1 3 6-7 12-14 16-INF\n"); |
jieluo@google.com | 8d6f04a | 2014-08-06 20:49:30 +0000 | [diff] [blame] | 1500 | #endif |
jieluo@google.com | 4de8f55 | 2014-07-18 00:47:59 +0000 | [diff] [blame] | 1501 | } |
| 1502 | |
temporal | 779f61c | 2008-08-13 03:15:00 +0000 | [diff] [blame] | 1503 | // =================================================================== |
| 1504 | |
| 1505 | // Test for --encode and --decode. Note that it would be easier to do this |
| 1506 | // test as a shell script, but we'd like to be able to run the test on |
| 1507 | // platforms that don't have a Bourne-compatible shell available (especially |
| 1508 | // Windows/MSVC). |
| 1509 | class EncodeDecodeTest : public testing::Test { |
| 1510 | protected: |
| 1511 | virtual void SetUp() { |
| 1512 | duped_stdin_ = dup(STDIN_FILENO); |
| 1513 | } |
| 1514 | |
| 1515 | virtual void TearDown() { |
| 1516 | dup2(duped_stdin_, STDIN_FILENO); |
| 1517 | close(duped_stdin_); |
| 1518 | } |
| 1519 | |
| 1520 | void RedirectStdinFromText(const string& input) { |
| 1521 | string filename = TestTempDir() + "/test_stdin"; |
jieluo@google.com | 4de8f55 | 2014-07-18 00:47:59 +0000 | [diff] [blame] | 1522 | GOOGLE_CHECK_OK(File::SetContents(filename, input, true)); |
temporal | 779f61c | 2008-08-13 03:15:00 +0000 | [diff] [blame] | 1523 | GOOGLE_CHECK(RedirectStdinFromFile(filename)); |
| 1524 | } |
| 1525 | |
| 1526 | bool RedirectStdinFromFile(const string& filename) { |
| 1527 | int fd = open(filename.c_str(), O_RDONLY); |
| 1528 | if (fd < 0) return false; |
| 1529 | dup2(fd, STDIN_FILENO); |
| 1530 | close(fd); |
| 1531 | return true; |
| 1532 | } |
| 1533 | |
| 1534 | // Remove '\r' characters from text. |
| 1535 | string StripCR(const string& text) { |
| 1536 | string result; |
| 1537 | |
| 1538 | for (int i = 0; i < text.size(); i++) { |
| 1539 | if (text[i] != '\r') { |
| 1540 | result.push_back(text[i]); |
| 1541 | } |
| 1542 | } |
| 1543 | |
| 1544 | return result; |
| 1545 | } |
| 1546 | |
| 1547 | enum Type { TEXT, BINARY }; |
| 1548 | enum ReturnCode { SUCCESS, ERROR }; |
| 1549 | |
| 1550 | bool Run(const string& command) { |
| 1551 | vector<string> args; |
| 1552 | args.push_back("protoc"); |
| 1553 | SplitStringUsing(command, " ", &args); |
| 1554 | args.push_back("--proto_path=" + TestSourceDir()); |
| 1555 | |
Feng Xiao | f157a56 | 2014-11-14 11:50:31 -0800 | [diff] [blame] | 1556 | google::protobuf::scoped_array<const char * > argv(new const char* [args.size()]); |
temporal | 779f61c | 2008-08-13 03:15:00 +0000 | [diff] [blame] | 1557 | for (int i = 0; i < args.size(); i++) { |
| 1558 | argv[i] = args[i].c_str(); |
| 1559 | } |
| 1560 | |
| 1561 | CommandLineInterface cli; |
| 1562 | cli.SetInputsAreProtoPathRelative(true); |
| 1563 | |
| 1564 | CaptureTestStdout(); |
| 1565 | CaptureTestStderr(); |
| 1566 | |
| 1567 | int result = cli.Run(args.size(), argv.get()); |
| 1568 | |
| 1569 | captured_stdout_ = GetCapturedTestStdout(); |
| 1570 | captured_stderr_ = GetCapturedTestStderr(); |
| 1571 | |
| 1572 | return result == 0; |
| 1573 | } |
| 1574 | |
| 1575 | void ExpectStdoutMatchesBinaryFile(const string& filename) { |
| 1576 | string expected_output; |
jieluo@google.com | 4de8f55 | 2014-07-18 00:47:59 +0000 | [diff] [blame] | 1577 | GOOGLE_CHECK_OK(File::GetContents(filename, &expected_output, true)); |
temporal | 779f61c | 2008-08-13 03:15:00 +0000 | [diff] [blame] | 1578 | |
| 1579 | // Don't use EXPECT_EQ because we don't want to print raw binary data to |
| 1580 | // stdout on failure. |
| 1581 | EXPECT_TRUE(captured_stdout_ == expected_output); |
| 1582 | } |
| 1583 | |
| 1584 | void ExpectStdoutMatchesTextFile(const string& filename) { |
| 1585 | string expected_output; |
jieluo@google.com | 4de8f55 | 2014-07-18 00:47:59 +0000 | [diff] [blame] | 1586 | GOOGLE_CHECK_OK(File::GetContents(filename, &expected_output, true)); |
temporal | 779f61c | 2008-08-13 03:15:00 +0000 | [diff] [blame] | 1587 | |
| 1588 | ExpectStdoutMatchesText(expected_output); |
| 1589 | } |
| 1590 | |
| 1591 | void ExpectStdoutMatchesText(const string& expected_text) { |
| 1592 | EXPECT_EQ(StripCR(expected_text), StripCR(captured_stdout_)); |
| 1593 | } |
| 1594 | |
| 1595 | void ExpectStderrMatchesText(const string& expected_text) { |
| 1596 | EXPECT_EQ(StripCR(expected_text), StripCR(captured_stderr_)); |
| 1597 | } |
| 1598 | |
| 1599 | private: |
| 1600 | int duped_stdin_; |
| 1601 | string captured_stdout_; |
| 1602 | string captured_stderr_; |
| 1603 | }; |
| 1604 | |
| 1605 | TEST_F(EncodeDecodeTest, Encode) { |
jieluo@google.com | 4de8f55 | 2014-07-18 00:47:59 +0000 | [diff] [blame] | 1606 | RedirectStdinFromFile(TestSourceDir() + "/google/protobuf/" |
| 1607 | "testdata/text_format_unittest_data_oneof_implemented.txt"); |
temporal | 779f61c | 2008-08-13 03:15:00 +0000 | [diff] [blame] | 1608 | EXPECT_TRUE(Run("google/protobuf/unittest.proto " |
| 1609 | "--encode=protobuf_unittest.TestAllTypes")); |
| 1610 | ExpectStdoutMatchesBinaryFile(TestSourceDir() + |
jieluo@google.com | 4de8f55 | 2014-07-18 00:47:59 +0000 | [diff] [blame] | 1611 | "/google/protobuf/testdata/golden_message_oneof_implemented"); |
temporal | 779f61c | 2008-08-13 03:15:00 +0000 | [diff] [blame] | 1612 | ExpectStderrMatchesText(""); |
| 1613 | } |
| 1614 | |
| 1615 | TEST_F(EncodeDecodeTest, Decode) { |
| 1616 | RedirectStdinFromFile(TestSourceDir() + |
jieluo@google.com | 4de8f55 | 2014-07-18 00:47:59 +0000 | [diff] [blame] | 1617 | "/google/protobuf/testdata/golden_message_oneof_implemented"); |
temporal | 779f61c | 2008-08-13 03:15:00 +0000 | [diff] [blame] | 1618 | EXPECT_TRUE(Run("google/protobuf/unittest.proto " |
| 1619 | "--decode=protobuf_unittest.TestAllTypes")); |
| 1620 | ExpectStdoutMatchesTextFile(TestSourceDir() + |
jieluo@google.com | 4de8f55 | 2014-07-18 00:47:59 +0000 | [diff] [blame] | 1621 | "/google/protobuf/" |
| 1622 | "testdata/text_format_unittest_data_oneof_implemented.txt"); |
temporal | 779f61c | 2008-08-13 03:15:00 +0000 | [diff] [blame] | 1623 | ExpectStderrMatchesText(""); |
| 1624 | } |
| 1625 | |
| 1626 | TEST_F(EncodeDecodeTest, Partial) { |
| 1627 | RedirectStdinFromText(""); |
| 1628 | EXPECT_TRUE(Run("google/protobuf/unittest.proto " |
| 1629 | "--encode=protobuf_unittest.TestRequired")); |
| 1630 | ExpectStdoutMatchesText(""); |
| 1631 | ExpectStderrMatchesText( |
| 1632 | "warning: Input message is missing required fields: a, b, c\n"); |
| 1633 | } |
| 1634 | |
| 1635 | TEST_F(EncodeDecodeTest, DecodeRaw) { |
| 1636 | protobuf_unittest::TestAllTypes message; |
| 1637 | message.set_optional_int32(123); |
| 1638 | message.set_optional_string("foo"); |
| 1639 | string data; |
| 1640 | message.SerializeToString(&data); |
| 1641 | |
| 1642 | RedirectStdinFromText(data); |
| 1643 | EXPECT_TRUE(Run("--decode_raw")); |
| 1644 | ExpectStdoutMatchesText("1: 123\n" |
| 1645 | "14: \"foo\"\n"); |
| 1646 | ExpectStderrMatchesText(""); |
| 1647 | } |
| 1648 | |
| 1649 | TEST_F(EncodeDecodeTest, UnknownType) { |
| 1650 | EXPECT_FALSE(Run("google/protobuf/unittest.proto " |
| 1651 | "--encode=NoSuchType")); |
| 1652 | ExpectStdoutMatchesText(""); |
| 1653 | ExpectStderrMatchesText("Type not defined: NoSuchType\n"); |
| 1654 | } |
| 1655 | |
| 1656 | TEST_F(EncodeDecodeTest, ProtoParseError) { |
| 1657 | EXPECT_FALSE(Run("google/protobuf/no_such_file.proto " |
| 1658 | "--encode=NoSuchType")); |
| 1659 | ExpectStdoutMatchesText(""); |
| 1660 | ExpectStderrMatchesText( |
| 1661 | "google/protobuf/no_such_file.proto: File not found.\n"); |
| 1662 | } |
| 1663 | |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 1664 | } // anonymous namespace |
| 1665 | |
| 1666 | } // namespace compiler |
| 1667 | } // namespace protobuf |
Jisi Liu | 7a00a1e | 2015-02-21 17:28:51 -0800 | [diff] [blame] | 1668 | |
Jisi Liu | 885b612 | 2015-02-28 14:51:22 -0800 | [diff] [blame^] | 1669 | #endif // !GOOGLE_PROTOBUF_HEAP_CHECK_DRACONIAN |
| 1670 | } // namespace google |