diff options
author | kenton@google.com <kenton@google.com@630680e5-0e50-0410-840e-4b1c322b438d> | 2009-12-18 02:11:36 +0000 |
---|---|---|
committer | kenton@google.com <kenton@google.com@630680e5-0e50-0410-840e-4b1c322b438d> | 2009-12-18 02:11:36 +0000 |
commit | fccb146e3fe437b0df1e9c50d4b8e1080ddb4bd9 (patch) | |
tree | 9f2d9fe0267d96a54e541377ffeada3d0bff0d1d /src/google/protobuf/compiler/command_line_interface_unittest.cc | |
parent | d5cf7b55a6a1f959d1646785f63ca2b62da78079 (diff) | |
download | protobuf-fccb146e3fe437b0df1e9c50d4b8e1080ddb4bd9.tar.gz protobuf-fccb146e3fe437b0df1e9c50d4b8e1080ddb4bd9.tar.bz2 protobuf-fccb146e3fe437b0df1e9c50d4b8e1080ddb4bd9.zip |
Massive roll-up of changes. See CHANGES.txt.
Diffstat (limited to 'src/google/protobuf/compiler/command_line_interface_unittest.cc')
-rw-r--r-- | src/google/protobuf/compiler/command_line_interface_unittest.cc | 576 |
1 files changed, 274 insertions, 302 deletions
diff --git a/src/google/protobuf/compiler/command_line_interface_unittest.cc b/src/google/protobuf/compiler/command_line_interface_unittest.cc index 9da41c02..83850cf9 100644 --- a/src/google/protobuf/compiler/command_line_interface_unittest.cc +++ b/src/google/protobuf/compiler/command_line_interface_unittest.cc @@ -47,10 +47,12 @@ #include <google/protobuf/io/zero_copy_stream.h> #include <google/protobuf/compiler/command_line_interface.h> #include <google/protobuf/compiler/code_generator.h> +#include <google/protobuf/compiler/mock_code_generator.h> #include <google/protobuf/io/printer.h> #include <google/protobuf/unittest.pb.h> #include <google/protobuf/testing/file.h> #include <google/protobuf/stubs/strutil.h> +#include <google/protobuf/stubs/substitute.h> #include <google/protobuf/testing/googletest.h> #include <gtest/gtest.h> @@ -83,28 +85,19 @@ class CommandLineInterfaceTest : public testing::Test { // ----------------------------------------------------------------- // Methods to set up the test (called before Run()). - class MockCodeGenerator; class NullCodeGenerator; - // Registers a MockCodeGenerator with the given name. - MockCodeGenerator* RegisterGenerator(const string& generator_name, - const string& flag_name, - const string& filename, - const string& help_text); - MockCodeGenerator* RegisterErrorGenerator(const string& generator_name, - const string& error_text, - const string& flag_name, - const string& filename, - const string& help_text); - - // Registers a CodeGenerator which will not actually generate anything, - // but records the parameter passed to the generator. - NullCodeGenerator* RegisterNullGenerator(const string& flag_name); + // Normally plugins are allowed for all tests. Call this to explicitly + // disable them. + void DisallowPlugins() { disallow_plugins_ = true; } // Create a temp file within temp_directory_ with the given name. // The containing directory is also created if necessary. void CreateTempFile(const string& name, const string& contents); + // Create a subdirectory within temp_directory_. + void CreateTempDir(const string& name); + void SetInputsAreProtoPathRelative(bool enable) { cli_.SetInputsAreProtoPathRelative(enable); } @@ -130,7 +123,8 @@ class CommandLineInterfaceTest : public testing::Test { bool HasAlternateErrorSubstring(const string& expected_substring); // Checks that MockCodeGenerator::Generate() was called in the given - // context. That is, this tests if the generator with the given name + // context (or the generator in test_plugin.cc, which produces the same + // output). That is, this tests if the generator with the given name // was called with the given parameter and proto file and produced the // given output file. This is checked by reading the output file and // checking that it contains the content that MockCodeGenerator would @@ -140,8 +134,17 @@ class CommandLineInterfaceTest : public testing::Test { void ExpectGenerated(const string& generator_name, const string& parameter, const string& proto_name, + const string& message_name); + void ExpectGenerated(const string& generator_name, + const string& parameter, + const string& proto_name, const string& message_name, - const string& output_file); + const string& output_directory); + void ExpectGeneratedWithInsertions(const string& generator_name, + const string& parameter, + const string& insertions, + const string& proto_name, + const string& message_name); void ReadDescriptorSet(const string& filename, FileDescriptorSet* descriptor_set); @@ -150,6 +153,9 @@ class CommandLineInterfaceTest : public testing::Test { // The object we are testing. CommandLineInterface cli_; + // Was DisallowPlugins() called? + bool disallow_plugins_; + // We create a directory within TestTempDir() in order to add extra // protection against accidentally deleting user files (since we recursively // delete this directory during the test). This is the full path of that @@ -166,40 +172,6 @@ class CommandLineInterfaceTest : public testing::Test { vector<CodeGenerator*> mock_generators_to_delete_; }; -// A mock CodeGenerator which outputs information about the context in which -// it was called, which can then be checked. Output is written to a filename -// constructed by concatenating the filename_prefix (given to the constructor) -// with the proto file name, separated by a '.'. -class CommandLineInterfaceTest::MockCodeGenerator : public CodeGenerator { - public: - // Create a MockCodeGenerator whose Generate() method returns true. - MockCodeGenerator(const string& name, const string& filename_prefix); - - // Create a MockCodeGenerator whose Generate() method returns false - // and sets the error string to the given string. - MockCodeGenerator(const string& name, const string& filename_prefix, - const string& error); - - ~MockCodeGenerator(); - - void set_expect_write_error(bool value) { - expect_write_error_ = value; - } - - // implements CodeGenerator ---------------------------------------- - bool Generate(const FileDescriptor* file, - const string& parameter, - OutputDirectory* output_directory, - string* error) const; - - private: - string name_; - string filename_prefix_; - bool return_error_; - string error_; - bool expect_write_error_; -}; - class CommandLineInterfaceTest::NullCodeGenerator : public CodeGenerator { public: NullCodeGenerator() : called_(false) {} @@ -237,6 +209,22 @@ void CommandLineInterfaceTest::SetUp() { // Create the temp directory. GOOGLE_CHECK(File::CreateDir(temp_directory_.c_str(), DEFAULT_FILE_MODE)); + + // Register generators. + CodeGenerator* generator = new MockCodeGenerator("test_generator"); + mock_generators_to_delete_.push_back(generator); + cli_.RegisterGenerator("--test_out", generator, "Test output."); + cli_.RegisterGenerator("-t", generator, "Test output."); + + generator = new MockCodeGenerator("alt_generator"); + mock_generators_to_delete_.push_back(generator); + cli_.RegisterGenerator("--alt_out", generator, "Alt output."); + + generator = new NullCodeGenerator(); + mock_generators_to_delete_.push_back(generator); + cli_.RegisterGenerator("--null_out", generator, "Null output."); + + disallow_plugins_ = false; } void CommandLineInterfaceTest::TearDown() { @@ -254,6 +242,11 @@ void CommandLineInterfaceTest::Run(const string& command) { vector<string> args; SplitStringUsing(command, " ", &args); + if (!disallow_plugins_) { + cli_.AllowPlugins("prefix-"); + args.push_back("--plugin=prefix-gen-plug=test_plugin"); + } + scoped_array<const char*> argv(new const char*[args.size()]); for (int i = 0; i < args.size(); i++) { @@ -270,44 +263,6 @@ void CommandLineInterfaceTest::Run(const string& command) { // ------------------------------------------------------------------- -CommandLineInterfaceTest::MockCodeGenerator* -CommandLineInterfaceTest::RegisterGenerator( - const string& generator_name, - const string& flag_name, - const string& filename, - const string& help_text) { - MockCodeGenerator* generator = - new MockCodeGenerator(generator_name, filename); - mock_generators_to_delete_.push_back(generator); - - cli_.RegisterGenerator(flag_name, generator, help_text); - return generator; -} - -CommandLineInterfaceTest::MockCodeGenerator* -CommandLineInterfaceTest::RegisterErrorGenerator( - const string& generator_name, - const string& error_text, - const string& flag_name, - const string& filename_prefix, - const string& help_text) { - MockCodeGenerator* generator = - new MockCodeGenerator(generator_name, filename_prefix, error_text); - mock_generators_to_delete_.push_back(generator); - - cli_.RegisterGenerator(flag_name, generator, help_text); - return generator; -} - -CommandLineInterfaceTest::NullCodeGenerator* -CommandLineInterfaceTest::RegisterNullGenerator( - const string& flag_name) { - NullCodeGenerator* generator = new NullCodeGenerator; - mock_generators_to_delete_.push_back(generator); - cli_.RegisterGenerator(flag_name, generator, ""); - return generator; -} - void CommandLineInterfaceTest::CreateTempFile( const string& name, const string& contents) { @@ -323,6 +278,10 @@ void CommandLineInterfaceTest::CreateTempFile( File::WriteStringToFileOrDie(contents, full_name); } +void CommandLineInterfaceTest::CreateTempDir(const string& name) { + File::RecursivelyCreateDir(temp_directory_ + "/" + name, 0777); +} + // ------------------------------------------------------------------- void CommandLineInterfaceTest::ExpectNoErrors() { @@ -352,21 +311,31 @@ void CommandLineInterfaceTest::ExpectGenerated( const string& generator_name, const string& parameter, const string& proto_name, + const string& message_name) { + MockCodeGenerator::ExpectGenerated( + generator_name, parameter, "", proto_name, message_name, temp_directory_); +} + +void CommandLineInterfaceTest::ExpectGenerated( + const string& generator_name, + const string& parameter, + const string& proto_name, const string& message_name, - const string& output_file_prefix) { - // Open and read the file. - string output_file = output_file_prefix + "." + proto_name; - string file_contents; - ASSERT_TRUE(File::ReadFileToString(temp_directory_ + "/" + output_file, - &file_contents)) - << "Failed to open file: " + output_file; + const string& output_directory) { + MockCodeGenerator::ExpectGenerated( + generator_name, parameter, "", proto_name, message_name, + temp_directory_ + "/" + output_directory); +} - // Check that the contents are as we expect. - string expected_contents = - generator_name + ": " + parameter + ", " + proto_name + ", " + - message_name + "\n"; - EXPECT_EQ(expected_contents, file_contents) - << "Output file did not have expected contents: " + output_file; +void CommandLineInterfaceTest::ExpectGeneratedWithInsertions( + const string& generator_name, + const string& parameter, + const string& insertions, + const string& proto_name, + const string& message_name) { + MockCodeGenerator::ExpectGenerated( + generator_name, parameter, insertions, proto_name, message_name, + temp_directory_); } void CommandLineInterfaceTest::ReadDescriptorSet( @@ -383,77 +352,52 @@ void CommandLineInterfaceTest::ReadDescriptorSet( // =================================================================== -CommandLineInterfaceTest::MockCodeGenerator::MockCodeGenerator( - const string& name, const string& filename_prefix) - : name_(name), - filename_prefix_(filename_prefix), - return_error_(false), - expect_write_error_(false) { -} - -CommandLineInterfaceTest::MockCodeGenerator::MockCodeGenerator( - const string& name, const string& filename_prefix, const string& error) - : name_(name), - filename_prefix_(filename_prefix), - return_error_(true), - error_(error), - expect_write_error_(false) { -} +TEST_F(CommandLineInterfaceTest, BasicOutput) { + // Test that the common case works. -CommandLineInterfaceTest::MockCodeGenerator::~MockCodeGenerator() {} + CreateTempFile("foo.proto", + "syntax = \"proto2\";\n" + "message Foo {}\n"); -bool CommandLineInterfaceTest::MockCodeGenerator::Generate( - const FileDescriptor* file, - const string& parameter, - OutputDirectory* output_directory, - string* error) const { - scoped_ptr<io::ZeroCopyOutputStream> output( - output_directory->Open(filename_prefix_ + "." + file->name())); - io::Printer printer(output.get(), '$'); - map<string, string> vars; - vars["name"] = name_; - vars["parameter"] = parameter; - vars["proto_name"] = file->name(); - vars["message_name"] = file->message_type_count() > 0 ? - file->message_type(0)->full_name().c_str() : "(none)"; - - printer.Print(vars, "$name$: $parameter$, $proto_name$, $message_name$\n"); - - if (expect_write_error_) { - EXPECT_TRUE(printer.failed()); - } else { - EXPECT_FALSE(printer.failed()); - } + Run("protocol_compiler --test_out=$tmpdir " + "--proto_path=$tmpdir foo.proto"); - *error = error_; - return !return_error_; + ExpectNoErrors(); + ExpectGenerated("test_generator", "", "foo.proto", "Foo"); } -// =================================================================== +TEST_F(CommandLineInterfaceTest, BasicPlugin) { + // Test that basic plugins work. -TEST_F(CommandLineInterfaceTest, BasicOutput) { - // Test that the common case works. + CreateTempFile("foo.proto", + "syntax = \"proto2\";\n" + "message Foo {}\n"); - RegisterGenerator("test_generator", "--test_out", - "output.test", "Test output."); + Run("protocol_compiler --plug_out=$tmpdir " + "--proto_path=$tmpdir foo.proto"); + + ExpectNoErrors(); + ExpectGenerated("test_plugin", "", "foo.proto", "Foo"); +} + +TEST_F(CommandLineInterfaceTest, GeneratorAndPlugin) { + // Invoke a generator and a plugin at the same time. CreateTempFile("foo.proto", "syntax = \"proto2\";\n" "message Foo {}\n"); - Run("protocol_compiler --test_out=$tmpdir " + Run("protocol_compiler --test_out=$tmpdir --plug_out=$tmpdir " "--proto_path=$tmpdir foo.proto"); ExpectNoErrors(); - ExpectGenerated("test_generator", "", "foo.proto", "Foo", "output.test"); + ExpectGenerated("test_generator", "", "foo.proto", "Foo"); + ExpectGenerated("test_plugin", "", "foo.proto", "Foo"); } TEST_F(CommandLineInterfaceTest, MultipleInputs) { // Test parsing multiple input files. - RegisterGenerator("test_generator", "--test_out", - "output.test", "Test output."); - CreateTempFile("foo.proto", "syntax = \"proto2\";\n" "message Foo {}\n"); @@ -461,48 +405,68 @@ TEST_F(CommandLineInterfaceTest, MultipleInputs) { "syntax = \"proto2\";\n" "message Bar {}\n"); - Run("protocol_compiler --test_out=$tmpdir " + Run("protocol_compiler --test_out=$tmpdir --plug_out=$tmpdir " "--proto_path=$tmpdir foo.proto bar.proto"); ExpectNoErrors(); - ExpectGenerated("test_generator", "", "foo.proto", "Foo", "output.test"); - ExpectGenerated("test_generator", "", "bar.proto", "Bar", "output.test"); + ExpectGenerated("test_generator", "", "foo.proto", "Foo"); + ExpectGenerated("test_generator", "", "bar.proto", "Bar"); } TEST_F(CommandLineInterfaceTest, CreateDirectory) { // Test that when we output to a sub-directory, it is created. - RegisterGenerator("test_generator", "--test_out", - "bar/baz/output.test", "Test output."); - - CreateTempFile("foo.proto", + CreateTempFile("bar/baz/foo.proto", "syntax = \"proto2\";\n" "message Foo {}\n"); + CreateTempDir("out"); + CreateTempDir("plugout"); - Run("protocol_compiler --test_out=$tmpdir " - "--proto_path=$tmpdir foo.proto"); + Run("protocol_compiler --test_out=$tmpdir/out --plug_out=$tmpdir/plugout " + "--proto_path=$tmpdir bar/baz/foo.proto"); ExpectNoErrors(); - ExpectGenerated("test_generator", "", - "foo.proto", "Foo", "bar/baz/output.test"); + ExpectGenerated("test_generator", "", "bar/baz/foo.proto", "Foo", "out"); + ExpectGenerated("test_plugin", "", "bar/baz/foo.proto", "Foo", "plugout"); } TEST_F(CommandLineInterfaceTest, GeneratorParameters) { // Test that generator parameters are correctly parsed from the command line. - RegisterGenerator("test_generator", "--test_out", - "output.test", "Test output."); - CreateTempFile("foo.proto", "syntax = \"proto2\";\n" "message Foo {}\n"); Run("protocol_compiler --test_out=TestParameter:$tmpdir " + "--plug_out=TestPluginParameter:$tmpdir " + "--proto_path=$tmpdir foo.proto"); + + ExpectNoErrors(); + ExpectGenerated("test_generator", "TestParameter", "foo.proto", "Foo"); + ExpectGenerated("test_plugin", "TestPluginParameter", "foo.proto", "Foo"); +} + +TEST_F(CommandLineInterfaceTest, Insert) { + // Test running a generator that inserts code into another's output. + + CreateTempFile("foo.proto", + "syntax = \"proto2\";\n" + "message Foo {}\n"); + + Run("protocol_compiler " + "--test_out=TestParameter:$tmpdir " + "--plug_out=TestPluginParameter:$tmpdir " + "--test_out=insert=test_generator,test_plugin:$tmpdir " + "--plug_out=insert=test_generator,test_plugin:$tmpdir " "--proto_path=$tmpdir foo.proto"); ExpectNoErrors(); - ExpectGenerated("test_generator", "TestParameter", - "foo.proto", "Foo", "output.test"); + ExpectGeneratedWithInsertions( + "test_generator", "TestParameter", "test_generator,test_plugin", + "foo.proto", "Foo"); + ExpectGeneratedWithInsertions( + "test_plugin", "TestPluginParameter", "test_generator,test_plugin", + "foo.proto", "Foo"); } #if defined(_WIN32) || defined(__CYGWIN__) @@ -510,12 +474,10 @@ TEST_F(CommandLineInterfaceTest, GeneratorParameters) { TEST_F(CommandLineInterfaceTest, WindowsOutputPath) { // Test that the output path can be a Windows-style path. - NullCodeGenerator* generator = RegisterNullGenerator("--test_out"); - CreateTempFile("foo.proto", "syntax = \"proto2\";\n"); - Run("protocol_compiler --test_out=C:\\ " + Run("protocol_compiler --null_out=C:\\ " "--proto_path=$tmpdir foo.proto"); ExpectNoErrors(); @@ -526,12 +488,10 @@ TEST_F(CommandLineInterfaceTest, WindowsOutputPath) { TEST_F(CommandLineInterfaceTest, WindowsOutputPathAndParameter) { // Test that we can have a windows-style output path and a parameter. - NullCodeGenerator* generator = RegisterNullGenerator("--test_out"); - CreateTempFile("foo.proto", "syntax = \"proto2\";\n"); - Run("protocol_compiler --test_out=bar:C:\\ " + Run("protocol_compiler --null_out=bar:C:\\ " "--proto_path=$tmpdir foo.proto"); ExpectNoErrors(); @@ -543,9 +503,6 @@ TEST_F(CommandLineInterfaceTest, TrailingBackslash) { // Test that the directories can end in backslashes. Some users claim this // doesn't work on their system. - RegisterGenerator("test_generator", "--test_out", - "output.test", "Test output."); - CreateTempFile("foo.proto", "syntax = \"proto2\";\n" "message Foo {}\n"); @@ -554,7 +511,7 @@ TEST_F(CommandLineInterfaceTest, TrailingBackslash) { "--proto_path=$tmpdir\\ foo.proto"); ExpectNoErrors(); - ExpectGenerated("test_generator", "", "foo.proto", "Foo", "output.test"); + ExpectGenerated("test_generator", "", "foo.proto", "Foo"); } #endif // defined(_WIN32) || defined(__CYGWIN__) @@ -562,9 +519,6 @@ TEST_F(CommandLineInterfaceTest, TrailingBackslash) { TEST_F(CommandLineInterfaceTest, PathLookup) { // Test that specifying multiple directories in the proto search path works. - RegisterGenerator("test_generator", "--test_out", - "output.test", "Test output."); - CreateTempFile("b/bar.proto", "syntax = \"proto2\";\n" "message Bar {}\n"); @@ -580,15 +534,12 @@ TEST_F(CommandLineInterfaceTest, PathLookup) { "--proto_path=$tmpdir/a --proto_path=$tmpdir/b foo.proto"); ExpectNoErrors(); - ExpectGenerated("test_generator", "", "foo.proto", "Foo", "output.test"); + ExpectGenerated("test_generator", "", "foo.proto", "Foo"); } TEST_F(CommandLineInterfaceTest, ColonDelimitedPath) { // Same as PathLookup, but we provide the proto_path in a single flag. - RegisterGenerator("test_generator", "--test_out", - "output.test", "Test output."); - CreateTempFile("b/bar.proto", "syntax = \"proto2\";\n" "message Bar {}\n"); @@ -613,15 +564,12 @@ TEST_F(CommandLineInterfaceTest, ColonDelimitedPath) { #undef PATH_SEPARATOR ExpectNoErrors(); - ExpectGenerated("test_generator", "", "foo.proto", "Foo", "output.test"); + ExpectGenerated("test_generator", "", "foo.proto", "Foo"); } TEST_F(CommandLineInterfaceTest, NonRootMapping) { // Test setting up a search path mapping a directory to a non-root location. - RegisterGenerator("test_generator", "--test_out", - "output.test", "Test output."); - CreateTempFile("foo.proto", "syntax = \"proto2\";\n" "message Foo {}\n"); @@ -630,42 +578,34 @@ TEST_F(CommandLineInterfaceTest, NonRootMapping) { "--proto_path=bar=$tmpdir bar/foo.proto"); ExpectNoErrors(); - ExpectGenerated("test_generator", "", "bar/foo.proto", "Foo", "output.test"); + ExpectGenerated("test_generator", "", "bar/foo.proto", "Foo"); } TEST_F(CommandLineInterfaceTest, MultipleGenerators) { // Test that we can have multiple generators and use both in one invocation, // each with a different output directory. - RegisterGenerator("test_generator_1", "--test1_out", - "output1.test", "Test output 1."); - RegisterGenerator("test_generator_2", "--test2_out", - "output2.test", "Test output 2."); - CreateTempFile("foo.proto", "syntax = \"proto2\";\n" "message Foo {}\n"); // Create the "a" and "b" sub-directories. - CreateTempFile("a/dummy", ""); - CreateTempFile("b/dummy", ""); + CreateTempDir("a"); + CreateTempDir("b"); Run("protocol_compiler " - "--test1_out=$tmpdir/a " - "--test2_out=$tmpdir/b " + "--test_out=$tmpdir/a " + "--alt_out=$tmpdir/b " "--proto_path=$tmpdir foo.proto"); ExpectNoErrors(); - ExpectGenerated("test_generator_1", "", "foo.proto", "Foo", "a/output1.test"); - ExpectGenerated("test_generator_2", "", "foo.proto", "Foo", "b/output2.test"); + ExpectGenerated("test_generator", "", "foo.proto", "Foo", "a"); + ExpectGenerated("alt_generator", "", "foo.proto", "Foo", "b"); } TEST_F(CommandLineInterfaceTest, DisallowServicesNoServices) { // Test that --disallow_services doesn't cause a problem when there are no // services. - RegisterGenerator("test_generator", "--test_out", - "output.test", "Test output."); - CreateTempFile("foo.proto", "syntax = \"proto2\";\n" "message Foo {}\n"); @@ -674,15 +614,12 @@ TEST_F(CommandLineInterfaceTest, DisallowServicesNoServices) { "--proto_path=$tmpdir foo.proto"); ExpectNoErrors(); - ExpectGenerated("test_generator", "", "foo.proto", "Foo", "output.test"); + ExpectGenerated("test_generator", "", "foo.proto", "Foo"); } TEST_F(CommandLineInterfaceTest, DisallowServicesHasService) { // Test that --disallow_services produces an error when there are services. - RegisterGenerator("test_generator", "--test_out", - "output.test", "Test output."); - CreateTempFile("foo.proto", "syntax = \"proto2\";\n" "message Foo {}\n" @@ -697,9 +634,6 @@ TEST_F(CommandLineInterfaceTest, DisallowServicesHasService) { TEST_F(CommandLineInterfaceTest, AllowServicesHasService) { // Test that services work fine as long as --disallow_services is not used. - RegisterGenerator("test_generator", "--test_out", - "output.test", "Test output."); - CreateTempFile("foo.proto", "syntax = \"proto2\";\n" "message Foo {}\n" @@ -709,7 +643,7 @@ TEST_F(CommandLineInterfaceTest, AllowServicesHasService) { "--proto_path=$tmpdir foo.proto"); ExpectNoErrors(); - ExpectGenerated("test_generator", "", "foo.proto", "Foo", "output.test"); + ExpectGenerated("test_generator", "", "foo.proto", "Foo"); } TEST_F(CommandLineInterfaceTest, CwdRelativeInputs) { @@ -717,9 +651,6 @@ TEST_F(CommandLineInterfaceTest, CwdRelativeInputs) { SetInputsAreProtoPathRelative(false); - RegisterGenerator("test_generator", "--test_out", - "output.test", "Test output."); - CreateTempFile("foo.proto", "syntax = \"proto2\";\n" "message Foo {}\n"); @@ -728,7 +659,7 @@ TEST_F(CommandLineInterfaceTest, CwdRelativeInputs) { "--proto_path=$tmpdir $tmpdir/foo.proto"); ExpectNoErrors(); - ExpectGenerated("test_generator", "", "foo.proto", "Foo", "output.test"); + ExpectGenerated("test_generator", "", "foo.proto", "Foo"); } TEST_F(CommandLineInterfaceTest, WriteDescriptorSet) { @@ -787,9 +718,6 @@ TEST_F(CommandLineInterfaceTest, WriteTransitiveDescriptorSet) { TEST_F(CommandLineInterfaceTest, ParseErrors) { // Test that parse errors are reported. - RegisterGenerator("test_generator", "--test_out", - "output.test", "Test output."); - CreateTempFile("foo.proto", "syntax = \"proto2\";\n" "badsyntax\n"); @@ -804,9 +732,6 @@ TEST_F(CommandLineInterfaceTest, ParseErrors) { TEST_F(CommandLineInterfaceTest, ParseErrorsMultipleFiles) { // Test that parse errors are reported from multiple files. - RegisterGenerator("test_generator", "--test_out", - "output.test", "Test output."); - // We set up files such that foo.proto actually depends on bar.proto in // two ways: Directly and through baz.proto. bar.proto's errors should // only be reported once. @@ -834,9 +759,6 @@ TEST_F(CommandLineInterfaceTest, ParseErrorsMultipleFiles) { TEST_F(CommandLineInterfaceTest, InputNotFoundError) { // Test what happens if the input file is not found. - RegisterGenerator("test_generator", "--test_out", - "output.test", "Test output."); - Run("protocol_compiler --test_out=$tmpdir " "--proto_path=$tmpdir foo.proto"); @@ -850,9 +772,6 @@ TEST_F(CommandLineInterfaceTest, CwdRelativeInputNotFoundError) { SetInputsAreProtoPathRelative(false); - RegisterGenerator("test_generator", "--test_out", - "output.test", "Test output."); - Run("protocol_compiler --test_out=$tmpdir " "--proto_path=$tmpdir $tmpdir/foo.proto"); @@ -866,9 +785,6 @@ TEST_F(CommandLineInterfaceTest, CwdRelativeInputNotMappedError) { SetInputsAreProtoPathRelative(false); - RegisterGenerator("test_generator", "--test_out", - "output.test", "Test output."); - CreateTempFile("foo.proto", "syntax = \"proto2\";\n" "message Foo {}\n"); @@ -895,9 +811,6 @@ TEST_F(CommandLineInterfaceTest, CwdRelativeInputNotFoundAndNotMappedError) { SetInputsAreProtoPathRelative(false); - RegisterGenerator("test_generator", "--test_out", - "output.test", "Test output."); - // Create a directory called "bar" so that we can point --proto_path at it. CreateTempFile("bar/dummy", ""); @@ -914,9 +827,6 @@ TEST_F(CommandLineInterfaceTest, CwdRelativeInputShadowedError) { SetInputsAreProtoPathRelative(false); - RegisterGenerator("test_generator", "--test_out", - "output.test", "Test output."); - CreateTempFile("foo/foo.proto", "syntax = \"proto2\";\n" "message Foo {}\n"); @@ -938,9 +848,6 @@ TEST_F(CommandLineInterfaceTest, CwdRelativeInputShadowedError) { TEST_F(CommandLineInterfaceTest, ProtoPathNotFoundError) { // Test what happens if the input file is not found. - RegisterGenerator("test_generator", "--test_out", - "output.test", "Test output."); - Run("protocol_compiler --test_out=$tmpdir " "--proto_path=$tmpdir/foo foo.proto"); @@ -952,9 +859,6 @@ TEST_F(CommandLineInterfaceTest, ProtoPathNotFoundError) { TEST_F(CommandLineInterfaceTest, MissingInputError) { // Test that we get an error if no inputs are given. - RegisterGenerator("test_generator", "--test_out", - "output.test", "Test output."); - Run("protocol_compiler --test_out=$tmpdir " "--proto_path=$tmpdir"); @@ -962,9 +866,6 @@ TEST_F(CommandLineInterfaceTest, MissingInputError) { } TEST_F(CommandLineInterfaceTest, MissingOutputError) { - RegisterGenerator("test_generator", "--test_out", - "output.test", "Test output."); - CreateTempFile("foo.proto", "syntax = \"proto2\";\n" "message Foo {}\n"); @@ -975,35 +876,56 @@ TEST_F(CommandLineInterfaceTest, MissingOutputError) { } TEST_F(CommandLineInterfaceTest, OutputWriteError) { - MockCodeGenerator* generator = - RegisterGenerator("test_generator", "--test_out", - "output.test", "Test output."); - generator->set_expect_write_error(true); - CreateTempFile("foo.proto", "syntax = \"proto2\";\n" "message Foo {}\n"); + string output_file = + MockCodeGenerator::GetOutputFileName("test_generator", "foo.proto"); + // Create a directory blocking our output location. - CreateTempFile("output.test.foo.proto/foo", ""); + CreateTempDir(output_file); Run("protocol_compiler --test_out=$tmpdir " "--proto_path=$tmpdir foo.proto"); + ExpectErrorSubstring("MockCodeGenerator detected write error."); + #if defined(_WIN32) && !defined(__CYGWIN__) // Windows with MSVCRT.dll produces EPERM instead of EISDIR. - if (HasAlternateErrorSubstring("output.test.foo.proto: Permission denied")) { + if (HasAlternateErrorSubstring(output_file + ": Permission denied")) { return; } #endif - ExpectErrorSubstring("output.test.foo.proto: Is a directory"); + ExpectErrorSubstring(output_file + ": Is a directory"); } -TEST_F(CommandLineInterfaceTest, OutputDirectoryNotFoundError) { - RegisterGenerator("test_generator", "--test_out", - "output.test", "Test output."); +TEST_F(CommandLineInterfaceTest, PluginOutputWriteError) { + CreateTempFile("foo.proto", + "syntax = \"proto2\";\n" + "message Foo {}\n"); + + string output_file = + MockCodeGenerator::GetOutputFileName("test_plugin", "foo.proto"); + + // Create a directory blocking our output location. + CreateTempDir(output_file); + + Run("protocol_compiler --plug_out=$tmpdir " + "--proto_path=$tmpdir foo.proto"); + +#if defined(_WIN32) && !defined(__CYGWIN__) + // Windows with MSVCRT.dll produces EPERM instead of EISDIR. + if (HasAlternateErrorSubstring(output_file + ": Permission denied")) { + return; + } +#endif + + ExpectErrorSubstring(output_file + ": Is a directory"); +} +TEST_F(CommandLineInterfaceTest, OutputDirectoryNotFoundError) { CreateTempFile("foo.proto", "syntax = \"proto2\";\n" "message Foo {}\n"); @@ -1011,14 +933,21 @@ TEST_F(CommandLineInterfaceTest, OutputDirectoryNotFoundError) { Run("protocol_compiler --test_out=$tmpdir/nosuchdir " "--proto_path=$tmpdir foo.proto"); - ExpectErrorSubstring("nosuchdir/: " - "No such file or directory"); + ExpectErrorSubstring("nosuchdir/: No such file or directory"); } -TEST_F(CommandLineInterfaceTest, OutputDirectoryIsFileError) { - RegisterGenerator("test_generator", "--test_out", - "output.test", "Test output."); +TEST_F(CommandLineInterfaceTest, PluginOutputDirectoryNotFoundError) { + CreateTempFile("foo.proto", + "syntax = \"proto2\";\n" + "message Foo {}\n"); + Run("protocol_compiler --plug_out=$tmpdir/nosuchdir " + "--proto_path=$tmpdir foo.proto"); + + ExpectErrorSubstring("nosuchdir/: No such file or directory"); +} + +TEST_F(CommandLineInterfaceTest, OutputDirectoryIsFileError) { CreateTempFile("foo.proto", "syntax = \"proto2\";\n" "message Foo {}\n"); @@ -1037,45 +966,109 @@ TEST_F(CommandLineInterfaceTest, OutputDirectoryIsFileError) { } TEST_F(CommandLineInterfaceTest, GeneratorError) { - RegisterErrorGenerator("error_generator", "Test error message.", - "--error_out", "output.test", "Test error output."); + CreateTempFile("foo.proto", + "syntax = \"proto2\";\n" + "message MockCodeGenerator_Error {}\n"); + + Run("protocol_compiler --test_out=$tmpdir " + "--proto_path=$tmpdir foo.proto"); + + ExpectErrorSubstring( + "--test_out: foo.proto: Saw message type MockCodeGenerator_Error."); +} + +TEST_F(CommandLineInterfaceTest, GeneratorPluginError) { + // Test a generator plugin that returns an error. CreateTempFile("foo.proto", "syntax = \"proto2\";\n" - "message Foo {}\n"); + "message MockCodeGenerator_Error {}\n"); - Run("protocol_compiler --error_out=$tmpdir " + Run("protocol_compiler --plug_out=TestParameter:$tmpdir " "--proto_path=$tmpdir foo.proto"); - ExpectErrorSubstring("--error_out: Test error message."); + ExpectErrorSubstring( + "--plug_out: foo.proto: Saw message type MockCodeGenerator_Error."); } -TEST_F(CommandLineInterfaceTest, HelpText) { - RegisterGenerator("test_generator", "--test_out", - "output.test", "Test output."); - RegisterErrorGenerator("error_generator", "Test error message.", - "--error_out", "output.test", "Test error output."); +TEST_F(CommandLineInterfaceTest, GeneratorPluginFail) { + // Test a generator plugin that exits with an error code. CreateTempFile("foo.proto", "syntax = \"proto2\";\n" + "message MockCodeGenerator_Exit {}\n"); + + Run("protocol_compiler --plug_out=TestParameter:$tmpdir " + "--proto_path=$tmpdir foo.proto"); + + ExpectErrorSubstring("Saw message type MockCodeGenerator_Exit."); + ExpectErrorSubstring( + "--plug_out: prefix-gen-plug: Plugin failed with status code 123."); +} + +TEST_F(CommandLineInterfaceTest, GeneratorPluginCrash) { + // Test a generator plugin that crashes. + + CreateTempFile("foo.proto", + "syntax = \"proto2\";\n" + "message MockCodeGenerator_Abort {}\n"); + + Run("protocol_compiler --plug_out=TestParameter:$tmpdir " + "--proto_path=$tmpdir foo.proto"); + + ExpectErrorSubstring("Saw message type MockCodeGenerator_Abort."); + + // Don't depend on the exact signal number. + ExpectErrorSubstring( + "--plug_out: prefix-gen-plug: Plugin killed by signal"); +} + +TEST_F(CommandLineInterfaceTest, GeneratorPluginNotFound) { + // Test what happens if the plugin isn't found. + + CreateTempFile("error.proto", + "syntax = \"proto2\";\n" + "message Foo {}\n"); + + Run("protocol_compiler --badplug_out=TestParameter:$tmpdir " + "--plugin=prefix-gen-badplug=no_such_file " + "--proto_path=$tmpdir error.proto"); + + ExpectErrorSubstring( + "no_such_file: program not found or is not executable"); + + ExpectErrorSubstring( + "--badplug_out: prefix-gen-badplug: Plugin failed with status code 1."); +} + +TEST_F(CommandLineInterfaceTest, GeneratorPluginNotAllowed) { + // Test what happens if plugins aren't allowed. + + CreateTempFile("error.proto", + "syntax = \"proto2\";\n" "message Foo {}\n"); + DisallowPlugins(); + Run("protocol_compiler --plug_out=TestParameter:$tmpdir " + "--proto_path=$tmpdir error.proto"); + + ExpectErrorSubstring("Unknown flag: --plug_out"); +} + +TEST_F(CommandLineInterfaceTest, HelpText) { Run("test_exec_name --help"); ExpectErrorSubstring("Usage: test_exec_name "); ExpectErrorSubstring("--test_out=OUT_DIR"); ExpectErrorSubstring("Test output."); - ExpectErrorSubstring("--error_out=OUT_DIR"); - ExpectErrorSubstring("Test error output."); + ExpectErrorSubstring("--alt_out=OUT_DIR"); + ExpectErrorSubstring("Alt output."); } TEST_F(CommandLineInterfaceTest, GccFormatErrors) { // Test --error_format=gcc (which is the default, but we want to verify // that it can be set explicitly). - RegisterGenerator("test_generator", "--test_out", - "output.test", "Test output."); - CreateTempFile("foo.proto", "syntax = \"proto2\";\n" "badsyntax\n"); @@ -1090,9 +1083,6 @@ TEST_F(CommandLineInterfaceTest, GccFormatErrors) { TEST_F(CommandLineInterfaceTest, MsvsFormatErrors) { // Test --error_format=msvs - RegisterGenerator("test_generator", "--test_out", - "output.test", "Test output."); - CreateTempFile("foo.proto", "syntax = \"proto2\";\n" "badsyntax\n"); @@ -1108,9 +1098,6 @@ TEST_F(CommandLineInterfaceTest, MsvsFormatErrors) { TEST_F(CommandLineInterfaceTest, InvalidErrorFormat) { // Test --error_format=msvs - RegisterGenerator("test_generator", "--test_out", - "output.test", "Test output."); - CreateTempFile("foo.proto", "syntax = \"proto2\";\n" "badsyntax\n"); @@ -1128,9 +1115,6 @@ TEST_F(CommandLineInterfaceTest, InvalidErrorFormat) { TEST_F(CommandLineInterfaceTest, ParseSingleCharacterFlag) { // Test that a single-character flag works. - RegisterGenerator("test_generator", "-t", - "output.test", "Test output."); - CreateTempFile("foo.proto", "syntax = \"proto2\";\n" "message Foo {}\n"); @@ -1139,15 +1123,12 @@ TEST_F(CommandLineInterfaceTest, ParseSingleCharacterFlag) { "--proto_path=$tmpdir foo.proto"); ExpectNoErrors(); - ExpectGenerated("test_generator", "", "foo.proto", "Foo", "output.test"); + ExpectGenerated("test_generator", "", "foo.proto", "Foo"); } TEST_F(CommandLineInterfaceTest, ParseSpaceDelimitedValue) { // Test that separating the flag value with a space works. - RegisterGenerator("test_generator", "--test_out", - "output.test", "Test output."); - CreateTempFile("foo.proto", "syntax = \"proto2\";\n" "message Foo {}\n"); @@ -1156,16 +1137,13 @@ TEST_F(CommandLineInterfaceTest, ParseSpaceDelimitedValue) { "--proto_path=$tmpdir foo.proto"); ExpectNoErrors(); - ExpectGenerated("test_generator", "", "foo.proto", "Foo", "output.test"); + ExpectGenerated("test_generator", "", "foo.proto", "Foo"); } TEST_F(CommandLineInterfaceTest, ParseSingleCharacterSpaceDelimitedValue) { // Test that separating the flag value with a space works for // single-character flags. - RegisterGenerator("test_generator", "-t", - "output.test", "Test output."); - CreateTempFile("foo.proto", "syntax = \"proto2\";\n" "message Foo {}\n"); @@ -1174,15 +1152,12 @@ TEST_F(CommandLineInterfaceTest, ParseSingleCharacterSpaceDelimitedValue) { "--proto_path=$tmpdir foo.proto"); ExpectNoErrors(); - ExpectGenerated("test_generator", "", "foo.proto", "Foo", "output.test"); + ExpectGenerated("test_generator", "", "foo.proto", "Foo"); } TEST_F(CommandLineInterfaceTest, MissingValueError) { // Test that we get an error if a flag is missing its value. - RegisterGenerator("test_generator", "--test_out", - "output.test", "Test output."); - Run("protocol_compiler --test_out --proto_path=$tmpdir foo.proto"); ExpectErrorText("Missing value for flag: --test_out\n"); @@ -1192,9 +1167,6 @@ TEST_F(CommandLineInterfaceTest, MissingValueAtEndError) { // Test that we get an error if the last argument is a flag requiring a // value. - RegisterGenerator("test_generator", "--test_out", - "output.test", "Test output."); - Run("protocol_compiler --test_out"); ExpectErrorText("Missing value for flag: --test_out\n"); |