12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516 |
- // Protocol Buffers - Google's data interchange format
- // Copyright 2008 Google Inc. All rights reserved.
- // https://developers.google.com/protocol-buffers/
- //
- // Redistribution and use in source and binary forms, with or without
- // modification, are permitted provided that the following conditions are
- // met:
- //
- // * Redistributions of source code must retain the above copyright
- // notice, this list of conditions and the following disclaimer.
- // * Redistributions in binary form must reproduce the above
- // copyright notice, this list of conditions and the following disclaimer
- // in the documentation and/or other materials provided with the
- // distribution.
- // * Neither the name of Google Inc. nor the names of its
- // contributors may be used to endorse or promote products derived from
- // this software without specific prior written permission.
- //
- // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- // Author: kenton@google.com (Kenton Varda)
- // Based on original Protocol Buffers design by
- // Sanjay Ghemawat, Jeff Dean, and others.
- #include <fcntl.h>
- #include <sys/stat.h>
- #include <sys/types.h>
- #ifndef _MSC_VER
- #include <unistd.h>
- #endif
- #include <memory>
- #include <vector>
- #include <google/protobuf/stubs/stringprintf.h>
- #include <google/protobuf/testing/file.h>
- #include <google/protobuf/testing/file.h>
- #include <google/protobuf/testing/file.h>
- #include <google/protobuf/compiler/mock_code_generator.h>
- #include <google/protobuf/compiler/subprocess.h>
- #include <google/protobuf/compiler/code_generator.h>
- #include <google/protobuf/compiler/command_line_interface.h>
- #include <google/protobuf/test_util2.h>
- #include <google/protobuf/unittest.pb.h>
- #include <google/protobuf/io/printer.h>
- #include <google/protobuf/io/zero_copy_stream.h>
- #include <google/protobuf/descriptor.pb.h>
- #include <google/protobuf/descriptor.h>
- #include <google/protobuf/testing/googletest.h>
- #include <gtest/gtest.h>
- #include <google/protobuf/stubs/substitute.h>
- #include <google/protobuf/io/io_win32.h>
- #include <google/protobuf/stubs/strutil.h>
- namespace google {
- namespace protobuf {
- namespace compiler {
- #if defined(_WIN32)
- // DO NOT include <io.h>, instead create functions in io_win32.{h,cc} and import
- // them like we do below.
- using google::protobuf::io::win32::access;
- using google::protobuf::io::win32::close;
- using google::protobuf::io::win32::dup;
- using google::protobuf::io::win32::dup2;
- using google::protobuf::io::win32::open;
- using google::protobuf::io::win32::write;
- #endif
- // Disable the whole test when we use tcmalloc for "draconian" heap checks, in
- // which case tcmalloc will print warnings that fail the plugin tests.
- #if !GOOGLE_PROTOBUF_HEAP_CHECK_DRACONIAN
- namespace {
- bool FileExists(const std::string& path) {
- return File::Exists(path);
- }
- class CommandLineInterfaceTest : public testing::Test {
- protected:
- virtual void SetUp();
- virtual void TearDown();
- // Runs the CommandLineInterface with the given command line. The
- // command is automatically split on spaces, and the string "$tmpdir"
- // is replaced with TestTempDir().
- void Run(const std::string& command);
- void RunWithArgs(std::vector<std::string> args);
- // -----------------------------------------------------------------
- // Methods to set up the test (called before Run()).
- class NullCodeGenerator;
- // 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 std::string& name, const std::string& contents);
- // Create a subdirectory within temp_directory_.
- void CreateTempDir(const std::string& name);
- #ifdef PROTOBUF_OPENSOURCE
- // Change working directory to temp directory.
- void SwitchToTempDirectory() {
- File::ChangeWorkingDirectory(temp_directory_);
- }
- #else // !PROTOBUF_OPENSOURCE
- // TODO(teboring): Figure out how to change and get working directory in
- // google3.
- #endif // !PROTOBUF_OPENSOURCE
- // -----------------------------------------------------------------
- // Methods to check the test results (called after Run()).
- // Checks that no text was written to stderr during Run(), and Run()
- // returned 0.
- void ExpectNoErrors();
- // Checks that Run() returned non-zero and the stderr output is exactly
- // the text given. expected_test may contain references to "$tmpdir",
- // which will be replaced by the temporary directory path.
- void ExpectErrorText(const std::string& expected_text);
- // Checks that Run() returned non-zero and the stderr contains the given
- // substring.
- void ExpectErrorSubstring(const std::string& expected_substring);
- // Checks that Run() returned zero and the stderr contains the given
- // substring.
- void ExpectWarningSubstring(const std::string& expected_substring);
- // Checks that the captured stdout is the same as the expected_text.
- void ExpectCapturedStdout(const std::string& expected_text);
- // Checks that Run() returned zero and the stdout contains the given
- // substring.
- void ExpectCapturedStdoutSubstringWithZeroReturnCode(
- const std::string& expected_substring);
- #if defined(_WIN32) && !defined(__CYGWIN__)
- // Returns true if ExpectErrorSubstring(expected_substring) would pass, but
- // does not fail otherwise.
- bool HasAlternateErrorSubstring(const std::string& expected_substring);
- #endif // _WIN32 && !__CYGWIN__
- // Checks that MockCodeGenerator::Generate() was called in the given
- // 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
- // generate given these inputs. message_name is the name of the first
- // message that appeared in the proto file; this is just to make extra
- // sure that the correct file was parsed.
- void ExpectGenerated(const std::string& generator_name,
- const std::string& parameter,
- const std::string& proto_name,
- const std::string& message_name);
- void ExpectGenerated(const std::string& generator_name,
- const std::string& parameter,
- const std::string& proto_name,
- const std::string& message_name,
- const std::string& output_directory);
- void ExpectGeneratedWithMultipleInputs(const std::string& generator_name,
- const std::string& all_proto_names,
- const std::string& proto_name,
- const std::string& message_name);
- void ExpectGeneratedWithInsertions(const std::string& generator_name,
- const std::string& parameter,
- const std::string& insertions,
- const std::string& proto_name,
- const std::string& message_name);
- void CheckGeneratedAnnotations(const std::string& name,
- const std::string& file);
- #if defined(_WIN32)
- void ExpectNullCodeGeneratorCalled(const std::string& parameter);
- #endif // _WIN32
- void ReadDescriptorSet(const std::string& filename,
- FileDescriptorSet* descriptor_set);
- void WriteDescriptorSet(const std::string& filename,
- const FileDescriptorSet* descriptor_set);
- void ExpectFileContent(const std::string& filename,
- const std::string& content);
- private:
- // 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
- // directory.
- std::string temp_directory_;
- // The result of Run().
- int return_code_;
- // The captured stderr output.
- std::string error_text_;
- // The captured stdout.
- std::string captured_stdout_;
- // Pointers which need to be deleted later.
- std::vector<CodeGenerator*> mock_generators_to_delete_;
- NullCodeGenerator* null_generator_;
- };
- class CommandLineInterfaceTest::NullCodeGenerator : public CodeGenerator {
- public:
- NullCodeGenerator() : called_(false) {}
- ~NullCodeGenerator() {}
- mutable bool called_;
- mutable std::string parameter_;
- // implements CodeGenerator ----------------------------------------
- bool Generate(const FileDescriptor* file, const std::string& parameter,
- GeneratorContext* context, std::string* error) const {
- called_ = true;
- parameter_ = parameter;
- return true;
- }
- };
- // ===================================================================
- void CommandLineInterfaceTest::SetUp() {
- temp_directory_ = TestTempDir() + "/proto2_cli_test_temp";
- // If the temp directory already exists, it must be left over from a
- // previous run. Delete it.
- if (FileExists(temp_directory_)) {
- File::DeleteRecursively(temp_directory_, NULL, NULL);
- }
- // Create the temp directory.
- GOOGLE_CHECK_OK(File::CreateDir(temp_directory_, 0777));
- // Register generators.
- CodeGenerator* generator = new MockCodeGenerator("test_generator");
- mock_generators_to_delete_.push_back(generator);
- cli_.RegisterGenerator("--test_out", "--test_opt", 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 = null_generator_ = new NullCodeGenerator();
- mock_generators_to_delete_.push_back(generator);
- cli_.RegisterGenerator("--null_out", generator, "Null output.");
- disallow_plugins_ = false;
- }
- void CommandLineInterfaceTest::TearDown() {
- // Delete the temp directory.
- if (FileExists(temp_directory_)) {
- File::DeleteRecursively(temp_directory_, NULL, NULL);
- }
- // Delete all the MockCodeGenerators.
- for (int i = 0; i < mock_generators_to_delete_.size(); i++) {
- delete mock_generators_to_delete_[i];
- }
- mock_generators_to_delete_.clear();
- }
- void CommandLineInterfaceTest::Run(const std::string& command) {
- RunWithArgs(Split(command, " ", true));
- }
- void CommandLineInterfaceTest::RunWithArgs(std::vector<std::string> args) {
- if (!disallow_plugins_) {
- cli_.AllowPlugins("prefix-");
- std::string plugin_path;
- #ifdef GOOGLE_PROTOBUF_TEST_PLUGIN_PATH
- plugin_path = GOOGLE_PROTOBUF_TEST_PLUGIN_PATH;
- #else
- const char* possible_paths[] = {
- // When building with shared libraries, libtool hides the real
- // executable
- // in .libs and puts a fake wrapper in the current directory.
- // Unfortunately, due to an apparent bug on Cygwin/MinGW, if one program
- // wrapped in this way (e.g. protobuf-tests.exe) tries to execute
- // another
- // program wrapped in this way (e.g. test_plugin.exe), the latter fails
- // with error code 127 and no explanation message. Presumably the
- // problem
- // is that the wrapper for protobuf-tests.exe set some environment
- // variables that confuse the wrapper for test_plugin.exe. Luckily, it
- // turns out that if we simply invoke the wrapped test_plugin.exe
- // directly, it works -- I guess the environment variables set by the
- // protobuf-tests.exe wrapper happen to be correct for it too. So we do
- // that.
- ".libs/test_plugin.exe", // Win32 w/autotool (Cygwin / MinGW)
- "test_plugin.exe", // Other Win32 (MSVC)
- "test_plugin", // Unix
- };
- for (int i = 0; i < GOOGLE_ARRAYSIZE(possible_paths); i++) {
- if (access(possible_paths[i], F_OK) == 0) {
- plugin_path = possible_paths[i];
- break;
- }
- }
- #endif
- if (plugin_path.empty()) {
- GOOGLE_LOG(ERROR)
- << "Plugin executable not found. Plugin tests are likely to fail.";
- } else {
- args.push_back("--plugin=prefix-gen-plug=" + plugin_path);
- }
- }
- std::unique_ptr<const char*[]> argv(new const char*[args.size()]);
- for (int i = 0; i < args.size(); i++) {
- args[i] = StringReplace(args[i], "$tmpdir", temp_directory_, true);
- argv[i] = args[i].c_str();
- }
- // TODO(jieluo): Cygwin doesn't work well if we try to capture stderr and
- // stdout at the same time. Need to figure out why and add this capture back
- // for Cygwin.
- #if !defined(__CYGWIN__)
- CaptureTestStdout();
- #endif
- CaptureTestStderr();
- return_code_ = cli_.Run(args.size(), argv.get());
- error_text_ = GetCapturedTestStderr();
- #if !defined(__CYGWIN__)
- captured_stdout_ = GetCapturedTestStdout();
- #endif
- }
- // -------------------------------------------------------------------
- void CommandLineInterfaceTest::CreateTempFile(const std::string& name,
- const std::string& contents) {
- // Create parent directory, if necessary.
- std::string::size_type slash_pos = name.find_last_of('/');
- if (slash_pos != std::string::npos) {
- std::string dir = name.substr(0, slash_pos);
- if (!FileExists(temp_directory_ + "/" + dir)) {
- GOOGLE_CHECK_OK(File::RecursivelyCreateDir(temp_directory_ + "/" + dir,
- 0777));
- }
- }
- // Write file.
- std::string full_name = temp_directory_ + "/" + name;
- GOOGLE_CHECK_OK(File::SetContents(
- full_name, StringReplace(contents, "$tmpdir", temp_directory_, true),
- true));
- }
- void CommandLineInterfaceTest::CreateTempDir(const std::string& name) {
- GOOGLE_CHECK_OK(File::RecursivelyCreateDir(temp_directory_ + "/" + name,
- 0777));
- }
- // -------------------------------------------------------------------
- void CommandLineInterfaceTest::ExpectNoErrors() {
- EXPECT_EQ(0, return_code_);
- EXPECT_EQ("", error_text_);
- }
- void CommandLineInterfaceTest::ExpectErrorText(
- const std::string& expected_text) {
- EXPECT_NE(0, return_code_);
- EXPECT_EQ(StringReplace(expected_text, "$tmpdir", temp_directory_, true),
- error_text_);
- }
- void CommandLineInterfaceTest::ExpectErrorSubstring(
- const std::string& expected_substring) {
- EXPECT_NE(0, return_code_);
- EXPECT_PRED_FORMAT2(testing::IsSubstring, expected_substring, error_text_);
- }
- void CommandLineInterfaceTest::ExpectWarningSubstring(
- const std::string& expected_substring) {
- EXPECT_EQ(0, return_code_);
- EXPECT_PRED_FORMAT2(testing::IsSubstring, expected_substring, error_text_);
- }
- #if defined(_WIN32) && !defined(__CYGWIN__)
- bool CommandLineInterfaceTest::HasAlternateErrorSubstring(
- const std::string& expected_substring) {
- EXPECT_NE(0, return_code_);
- return error_text_.find(expected_substring) != std::string::npos;
- }
- #endif // _WIN32 && !__CYGWIN__
- void CommandLineInterfaceTest::ExpectGenerated(
- const std::string& generator_name, const std::string& parameter,
- const std::string& proto_name, const std::string& message_name) {
- MockCodeGenerator::ExpectGenerated(generator_name, parameter, "", proto_name,
- message_name, proto_name, temp_directory_);
- }
- void CommandLineInterfaceTest::ExpectGenerated(
- const std::string& generator_name, const std::string& parameter,
- const std::string& proto_name, const std::string& message_name,
- const std::string& output_directory) {
- MockCodeGenerator::ExpectGenerated(generator_name, parameter, "", proto_name,
- message_name, proto_name,
- temp_directory_ + "/" + output_directory);
- }
- void CommandLineInterfaceTest::ExpectGeneratedWithMultipleInputs(
- const std::string& generator_name, const std::string& all_proto_names,
- const std::string& proto_name, const std::string& message_name) {
- MockCodeGenerator::ExpectGenerated(generator_name, "", "", proto_name,
- message_name, all_proto_names,
- temp_directory_);
- }
- void CommandLineInterfaceTest::ExpectGeneratedWithInsertions(
- const std::string& generator_name, const std::string& parameter,
- const std::string& insertions, const std::string& proto_name,
- const std::string& message_name) {
- MockCodeGenerator::ExpectGenerated(generator_name, parameter, insertions,
- proto_name, message_name, proto_name,
- temp_directory_);
- }
- void CommandLineInterfaceTest::CheckGeneratedAnnotations(
- const std::string& name, const std::string& file) {
- MockCodeGenerator::CheckGeneratedAnnotations(name, file, temp_directory_);
- }
- #if defined(_WIN32)
- void CommandLineInterfaceTest::ExpectNullCodeGeneratorCalled(
- const std::string& parameter) {
- EXPECT_TRUE(null_generator_->called_);
- EXPECT_EQ(parameter, null_generator_->parameter_);
- }
- #endif // _WIN32
- void CommandLineInterfaceTest::ReadDescriptorSet(
- const std::string& filename, FileDescriptorSet* descriptor_set) {
- std::string path = temp_directory_ + "/" + filename;
- std::string file_contents;
- GOOGLE_CHECK_OK(File::GetContents(path, &file_contents, true));
- if (!descriptor_set->ParseFromString(file_contents)) {
- FAIL() << "Could not parse file contents: " << path;
- }
- }
- void CommandLineInterfaceTest::WriteDescriptorSet(
- const std::string& filename, const FileDescriptorSet* descriptor_set) {
- std::string binary_proto;
- GOOGLE_CHECK(descriptor_set->SerializeToString(&binary_proto));
- CreateTempFile(filename, binary_proto);
- }
- void CommandLineInterfaceTest::ExpectCapturedStdout(
- const std::string& expected_text) {
- EXPECT_EQ(expected_text, captured_stdout_);
- }
- void CommandLineInterfaceTest::ExpectCapturedStdoutSubstringWithZeroReturnCode(
- const std::string& expected_substring) {
- EXPECT_EQ(0, return_code_);
- EXPECT_PRED_FORMAT2(testing::IsSubstring, expected_substring,
- captured_stdout_);
- }
- void CommandLineInterfaceTest::ExpectFileContent(const std::string& filename,
- const std::string& content) {
- std::string path = temp_directory_ + "/" + filename;
- std::string file_contents;
- GOOGLE_CHECK_OK(File::GetContents(path, &file_contents, true));
- EXPECT_EQ(StringReplace(content, "$tmpdir", temp_directory_, true),
- file_contents);
- }
- // ===================================================================
- TEST_F(CommandLineInterfaceTest, BasicOutput) {
- // Test that the common case works.
- CreateTempFile("foo.proto",
- "syntax = \"proto2\";\n"
- "message Foo {}\n");
- Run("protocol_compiler --test_out=$tmpdir "
- "--proto_path=$tmpdir foo.proto");
- ExpectNoErrors();
- ExpectGenerated("test_generator", "", "foo.proto", "Foo");
- }
- TEST_F(CommandLineInterfaceTest, BasicOutput_DescriptorSetIn) {
- // Test that the common case works.
- FileDescriptorSet file_descriptor_set;
- FileDescriptorProto* file_descriptor_proto = file_descriptor_set.add_file();
- file_descriptor_proto->set_name("foo.proto");
- file_descriptor_proto->add_message_type()->set_name("Foo");
- WriteDescriptorSet("foo.bin", &file_descriptor_set);
- Run("protocol_compiler --test_out=$tmpdir "
- "--descriptor_set_in=$tmpdir/foo.bin foo.proto");
- ExpectNoErrors();
- ExpectGenerated("test_generator", "", "foo.proto", "Foo");
- }
- TEST_F(CommandLineInterfaceTest, BasicPlugin) {
- // Test that basic plugins work.
- CreateTempFile("foo.proto",
- "syntax = \"proto2\";\n"
- "message Foo {}\n");
- Run("protocol_compiler --plug_out=$tmpdir "
- "--proto_path=$tmpdir foo.proto");
- ExpectNoErrors();
- ExpectGenerated("test_plugin", "", "foo.proto", "Foo");
- }
- TEST_F(CommandLineInterfaceTest, BasicPlugin_DescriptorSetIn) {
- // Test that basic plugins work.
- FileDescriptorSet file_descriptor_set;
- FileDescriptorProto* file_descriptor_proto = file_descriptor_set.add_file();
- file_descriptor_proto->set_name("foo.proto");
- file_descriptor_proto->add_message_type()->set_name("Foo");
- WriteDescriptorSet("foo.bin", &file_descriptor_set);
- Run("protocol_compiler --plug_out=$tmpdir "
- "--descriptor_set_in=$tmpdir/foo.bin 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 --plug_out=$tmpdir "
- "--proto_path=$tmpdir foo.proto");
- ExpectNoErrors();
- ExpectGenerated("test_generator", "", "foo.proto", "Foo");
- ExpectGenerated("test_plugin", "", "foo.proto", "Foo");
- }
- TEST_F(CommandLineInterfaceTest, GeneratorAndPlugin_DescriptorSetIn) {
- // Invoke a generator and a plugin at the same time.
- FileDescriptorSet file_descriptor_set;
- FileDescriptorProto* file_descriptor_proto = file_descriptor_set.add_file();
- file_descriptor_proto->set_name("foo.proto");
- file_descriptor_proto->add_message_type()->set_name("Foo");
- WriteDescriptorSet("foo.bin", &file_descriptor_set);
- Run("protocol_compiler --test_out=$tmpdir --plug_out=$tmpdir "
- "--descriptor_set_in=$tmpdir/foo.bin foo.proto");
- ExpectNoErrors();
- ExpectGenerated("test_generator", "", "foo.proto", "Foo");
- ExpectGenerated("test_plugin", "", "foo.proto", "Foo");
- }
- TEST_F(CommandLineInterfaceTest, MultipleInputs) {
- // Test parsing multiple input files.
- CreateTempFile("foo.proto",
- "syntax = \"proto2\";\n"
- "message Foo {}\n");
- CreateTempFile("bar.proto",
- "syntax = \"proto2\";\n"
- "message Bar {}\n");
- Run("protocol_compiler --test_out=$tmpdir --plug_out=$tmpdir "
- "--proto_path=$tmpdir foo.proto bar.proto");
- ExpectNoErrors();
- ExpectGeneratedWithMultipleInputs("test_generator", "foo.proto,bar.proto",
- "foo.proto", "Foo");
- ExpectGeneratedWithMultipleInputs("test_generator", "foo.proto,bar.proto",
- "bar.proto", "Bar");
- ExpectGeneratedWithMultipleInputs("test_plugin", "foo.proto,bar.proto",
- "foo.proto", "Foo");
- ExpectGeneratedWithMultipleInputs("test_plugin", "foo.proto,bar.proto",
- "bar.proto", "Bar");
- }
- TEST_F(CommandLineInterfaceTest, MultipleInputs_DescriptorSetIn) {
- // Test parsing multiple input files.
- FileDescriptorSet file_descriptor_set;
- FileDescriptorProto* file_descriptor_proto = file_descriptor_set.add_file();
- file_descriptor_proto->set_name("foo.proto");
- file_descriptor_proto->add_message_type()->set_name("Foo");
- file_descriptor_proto = file_descriptor_set.add_file();
- file_descriptor_proto->set_name("bar.proto");
- file_descriptor_proto->add_message_type()->set_name("Bar");
- WriteDescriptorSet("foo.bin", &file_descriptor_set);
- Run("protocol_compiler --test_out=$tmpdir --plug_out=$tmpdir "
- "--descriptor_set_in=$tmpdir/foo.bin foo.proto bar.proto");
- ExpectNoErrors();
- ExpectGeneratedWithMultipleInputs("test_generator", "foo.proto,bar.proto",
- "foo.proto", "Foo");
- ExpectGeneratedWithMultipleInputs("test_generator", "foo.proto,bar.proto",
- "bar.proto", "Bar");
- ExpectGeneratedWithMultipleInputs("test_plugin", "foo.proto,bar.proto",
- "foo.proto", "Foo");
- ExpectGeneratedWithMultipleInputs("test_plugin", "foo.proto,bar.proto",
- "bar.proto", "Bar");
- }
- TEST_F(CommandLineInterfaceTest, MultipleInputsWithImport) {
- // Test parsing multiple input files with an import of a separate file.
- CreateTempFile("foo.proto",
- "syntax = \"proto2\";\n"
- "message Foo {}\n");
- CreateTempFile("bar.proto",
- "syntax = \"proto2\";\n"
- "import \"baz.proto\";\n"
- "message Bar {\n"
- " optional Baz a = 1;\n"
- "}\n");
- CreateTempFile("baz.proto",
- "syntax = \"proto2\";\n"
- "message Baz {}\n");
- Run("protocol_compiler --test_out=$tmpdir --plug_out=$tmpdir "
- "--proto_path=$tmpdir foo.proto bar.proto");
- ExpectNoErrors();
- ExpectGeneratedWithMultipleInputs("test_generator", "foo.proto,bar.proto",
- "foo.proto", "Foo");
- ExpectGeneratedWithMultipleInputs("test_generator", "foo.proto,bar.proto",
- "bar.proto", "Bar");
- ExpectGeneratedWithMultipleInputs("test_plugin", "foo.proto,bar.proto",
- "foo.proto", "Foo");
- ExpectGeneratedWithMultipleInputs("test_plugin", "foo.proto,bar.proto",
- "bar.proto", "Bar");
- }
- TEST_F(CommandLineInterfaceTest, MultipleInputsWithImport_DescriptorSetIn) {
- // Test parsing multiple input files with an import of a separate file.
- FileDescriptorSet file_descriptor_set;
- FileDescriptorProto* file_descriptor_proto = file_descriptor_set.add_file();
- file_descriptor_proto->set_name("foo.proto");
- file_descriptor_proto->add_message_type()->set_name("Foo");
- file_descriptor_proto = file_descriptor_set.add_file();
- file_descriptor_proto->set_name("bar.proto");
- file_descriptor_proto->add_dependency("baz.proto");
- DescriptorProto* message = file_descriptor_proto->add_message_type();
- message->set_name("Bar");
- FieldDescriptorProto* field = message->add_field();
- field->set_type_name("Baz");
- field->set_name("a");
- field->set_number(1);
- WriteDescriptorSet("foo_and_bar.bin", &file_descriptor_set);
- file_descriptor_set.clear_file();
- file_descriptor_proto = file_descriptor_set.add_file();
- file_descriptor_proto->set_name("baz.proto");
- file_descriptor_proto->add_message_type()->set_name("Baz");
- file_descriptor_proto = file_descriptor_set.add_file();
- file_descriptor_proto->set_name("bat.proto");
- file_descriptor_proto->add_dependency("baz.proto");
- message = file_descriptor_proto->add_message_type();
- message->set_name("Bat");
- field = message->add_field();
- field->set_type_name("Baz");
- field->set_name("a");
- field->set_number(1);
- WriteDescriptorSet("baz_and_bat.bin", &file_descriptor_set);
- Run(strings::Substitute(
- "protocol_compiler --test_out=$$tmpdir --plug_out=$$tmpdir "
- "--descriptor_set_in=$0 foo.proto bar.proto",
- std::string("$tmpdir/foo_and_bar.bin") +
- CommandLineInterface::kPathSeparator + "$tmpdir/baz_and_bat.bin"));
- ExpectNoErrors();
- ExpectGeneratedWithMultipleInputs("test_generator", "foo.proto,bar.proto",
- "foo.proto", "Foo");
- ExpectGeneratedWithMultipleInputs("test_generator", "foo.proto,bar.proto",
- "bar.proto", "Bar");
- ExpectGeneratedWithMultipleInputs("test_plugin", "foo.proto,bar.proto",
- "foo.proto", "Foo");
- ExpectGeneratedWithMultipleInputs("test_plugin", "foo.proto,bar.proto",
- "bar.proto", "Bar");
- Run(strings::Substitute(
- "protocol_compiler --test_out=$$tmpdir --plug_out=$$tmpdir "
- "--descriptor_set_in=$0 baz.proto bat.proto",
- std::string("$tmpdir/foo_and_bar.bin") +
- CommandLineInterface::kPathSeparator + "$tmpdir/baz_and_bat.bin"));
- ExpectNoErrors();
- ExpectGeneratedWithMultipleInputs("test_generator", "baz.proto,bat.proto",
- "baz.proto", "Baz");
- ExpectGeneratedWithMultipleInputs("test_generator", "baz.proto,bat.proto",
- "bat.proto", "Bat");
- ExpectGeneratedWithMultipleInputs("test_plugin", "baz.proto,bat.proto",
- "baz.proto", "Baz");
- ExpectGeneratedWithMultipleInputs("test_plugin", "baz.proto,bat.proto",
- "bat.proto", "Bat");
- }
- TEST_F(CommandLineInterfaceTest,
- MultipleInputsWithImport_DescriptorSetIn_DuplicateFileDescriptor) {
- // Test parsing multiple input files with an import of a separate file.
- FileDescriptorSet file_descriptor_set;
- FileDescriptorProto foo_file_descriptor_proto;
- foo_file_descriptor_proto.set_name("foo.proto");
- foo_file_descriptor_proto.add_message_type()->set_name("Foo");
- file_descriptor_set.add_file()->CopyFrom(foo_file_descriptor_proto);
- FileDescriptorProto* file_descriptor_proto = file_descriptor_set.add_file();
- file_descriptor_proto->set_name("bar.proto");
- file_descriptor_proto->add_dependency("baz.proto");
- file_descriptor_proto->add_dependency("foo.proto");
- DescriptorProto* message = file_descriptor_proto->add_message_type();
- message->set_name("Bar");
- FieldDescriptorProto* field = message->add_field();
- field->set_type_name("Baz");
- field->set_name("a");
- field->set_number(1);
- field = message->add_field();
- field->set_type_name("Foo");
- field->set_name("f");
- field->set_number(2);
- WriteDescriptorSet("foo_and_bar.bin", &file_descriptor_set);
- file_descriptor_set.clear_file();
- file_descriptor_set.add_file()->CopyFrom(foo_file_descriptor_proto);
- file_descriptor_proto = file_descriptor_set.add_file();
- file_descriptor_proto->set_name("baz.proto");
- file_descriptor_proto->add_dependency("foo.proto");
- message = file_descriptor_proto->add_message_type();
- message->set_name("Baz");
- field = message->add_field();
- field->set_type_name("Foo");
- field->set_name("f");
- field->set_number(1);
- WriteDescriptorSet("foo_and_baz.bin", &file_descriptor_set);
- Run(strings::Substitute(
- "protocol_compiler --test_out=$$tmpdir --plug_out=$$tmpdir "
- "--descriptor_set_in=$0 bar.proto",
- std::string("$tmpdir/foo_and_bar.bin") +
- CommandLineInterface::kPathSeparator + "$tmpdir/foo_and_baz.bin"));
- ExpectNoErrors();
- ExpectGenerated("test_generator", "", "bar.proto", "Bar");
- ExpectGenerated("test_plugin", "", "bar.proto", "Bar");
- }
- TEST_F(CommandLineInterfaceTest,
- MultipleInputsWithImport_DescriptorSetIn_MissingImport) {
- // Test parsing multiple input files with an import of a separate file.
- FileDescriptorSet file_descriptor_set;
- FileDescriptorProto* file_descriptor_proto = file_descriptor_set.add_file();
- file_descriptor_proto->set_name("foo.proto");
- file_descriptor_proto->add_message_type()->set_name("Foo");
- file_descriptor_proto = file_descriptor_set.add_file();
- file_descriptor_proto->set_name("bar.proto");
- file_descriptor_proto->add_dependency("baz.proto");
- DescriptorProto* message = file_descriptor_proto->add_message_type();
- message->set_name("Bar");
- FieldDescriptorProto* field = message->add_field();
- field->set_type_name("Baz");
- field->set_name("a");
- field->set_number(1);
- WriteDescriptorSet("foo_and_bar.bin", &file_descriptor_set);
- file_descriptor_set.clear_file();
- file_descriptor_proto = file_descriptor_set.add_file();
- file_descriptor_proto->set_name("baz.proto");
- file_descriptor_proto->add_message_type()->set_name("Baz");
- WriteDescriptorSet("baz.bin", &file_descriptor_set);
- Run("protocol_compiler --test_out=$tmpdir --plug_out=$tmpdir "
- "--descriptor_set_in=$tmpdir/foo_and_bar.bin "
- "foo.proto bar.proto");
- ExpectErrorSubstring(
- "bar.proto: Import \"baz.proto\" was not found or had errors.");
- ExpectErrorSubstring("bar.proto: \"Baz\" is not defined.");
- }
- TEST_F(CommandLineInterfaceTest,
- OnlyReportsUnusedImportsForFilesBeingGenerated) {
- CreateTempFile("unused.proto",
- "syntax = \"proto2\";\n"
- "message Unused {}\n");
- CreateTempFile("bar.proto",
- "syntax = \"proto2\";\n"
- "import \"unused.proto\";\n"
- "message Bar {}\n");
- CreateTempFile("foo.proto",
- "syntax = \"proto2\";\n"
- "import \"bar.proto\";\n"
- "message Foo {\n"
- " optional Bar bar = 1;\n"
- "}\n");
- Run("protocol_compiler --test_out=$tmpdir "
- "--proto_path=$tmpdir foo.proto");
- ExpectNoErrors();
- }
- TEST_F(CommandLineInterfaceTest, ReportsTransitiveMisingImports_LeafFirst) {
- CreateTempFile("unused.proto",
- "syntax = \"proto2\";\n"
- "message Unused {}\n");
- CreateTempFile("bar.proto",
- "syntax = \"proto2\";\n"
- "import \"unused.proto\";\n"
- "message Bar {}\n");
- CreateTempFile("foo.proto",
- "syntax = \"proto2\";\n"
- "import \"bar.proto\";\n"
- "message Foo {\n"
- " optional Bar bar = 1;\n"
- "}\n");
- Run("protocol_compiler --test_out=$tmpdir "
- "--proto_path=$tmpdir bar.proto foo.proto");
- ExpectWarningSubstring(
- "bar.proto:2:1: warning: Import unused.proto but not used.");
- }
- TEST_F(CommandLineInterfaceTest, ReportsTransitiveMisingImports_LeafLast) {
- CreateTempFile("unused.proto",
- "syntax = \"proto2\";\n"
- "message Unused {}\n");
- CreateTempFile("bar.proto",
- "syntax = \"proto2\";\n"
- "import \"unused.proto\";\n"
- "message Bar {}\n");
- CreateTempFile("foo.proto",
- "syntax = \"proto2\";\n"
- "import \"bar.proto\";\n"
- "message Foo {\n"
- " optional Bar bar = 1;\n"
- "}\n");
- Run("protocol_compiler --test_out=$tmpdir "
- "--proto_path=$tmpdir foo.proto bar.proto");
- ExpectWarningSubstring(
- "bar.proto:2:1: warning: Import unused.proto but not used.");
- }
- TEST_F(CommandLineInterfaceTest, CreateDirectory) {
- // Test that when we output to a sub-directory, it is created.
- CreateTempFile("bar/baz/foo.proto",
- "syntax = \"proto2\";\n"
- "message Foo {}\n");
- CreateTempDir("out");
- CreateTempDir("plugout");
- Run("protocol_compiler --test_out=$tmpdir/out --plug_out=$tmpdir/plugout "
- "--proto_path=$tmpdir bar/baz/foo.proto");
- ExpectNoErrors();
- 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.
- 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, ExtraGeneratorParameters) {
- // Test that generator parameters specified with the option flag are
- // correctly passed to the code generator.
- CreateTempFile("foo.proto",
- "syntax = \"proto2\";\n"
- "message Foo {}\n");
- // Create the "a" and "b" sub-directories.
- CreateTempDir("a");
- CreateTempDir("b");
- Run("protocol_compiler "
- "--test_opt=foo1 "
- "--test_out=bar:$tmpdir/a "
- "--test_opt=foo2 "
- "--test_out=baz:$tmpdir/b "
- "--test_opt=foo3 "
- "--proto_path=$tmpdir foo.proto");
- ExpectNoErrors();
- ExpectGenerated("test_generator", "bar,foo1,foo2,foo3", "foo.proto", "Foo",
- "a");
- ExpectGenerated("test_generator", "baz,foo1,foo2,foo3", "foo.proto", "Foo",
- "b");
- }
- TEST_F(CommandLineInterfaceTest, ExtraPluginParameters) {
- // Test that generator parameters specified with the option flag are
- // correctly passed to the code generator.
- CreateTempFile("foo.proto",
- "syntax = \"proto2\";\n"
- "message Foo {}\n");
- // Create the "a" and "b" sub-directories.
- CreateTempDir("a");
- CreateTempDir("b");
- Run("protocol_compiler "
- "--plug_opt=foo1 "
- "--plug_out=bar:$tmpdir/a "
- "--plug_opt=foo2 "
- "--plug_out=baz:$tmpdir/b "
- "--plug_opt=foo3 "
- "--proto_path=$tmpdir foo.proto");
- ExpectNoErrors();
- ExpectGenerated("test_plugin", "bar,foo1,foo2,foo3", "foo.proto", "Foo", "a");
- ExpectGenerated("test_plugin", "baz,foo1,foo2,foo3", "foo.proto", "Foo", "b");
- }
- TEST_F(CommandLineInterfaceTest, UnrecognizedExtraParameters) {
- CreateTempFile("foo.proto",
- "syntax = \"proto2\";\n"
- "message Foo {}\n");
- Run("protocol_compiler --plug_out=TestParameter:$tmpdir "
- "--unknown_plug_a_opt=Foo "
- "--unknown_plug_b_opt=Bar "
- "--proto_path=$tmpdir foo.proto");
- ExpectErrorSubstring("Unknown flag: --unknown_plug_a_opt");
- ExpectErrorSubstring("Unknown flag: --unknown_plug_b_opt");
- }
- TEST_F(CommandLineInterfaceTest, ExtraPluginParametersForOutParameters) {
- // This doesn't rely on the plugin having been registred and instead that
- // the existence of --[name]_out is enough to make the --[name]_opt valid.
- // However, running out of process plugins found via the search path (i.e. -
- // not pre registered with --plugin) isn't support in this test suite, so we
- // list the options pre/post the _out directive, and then include _opt that
- // will be unknown, and confirm the failure output is about the expected
- // unknown directive, which means the other were accepted.
- // NOTE: UnrecognizedExtraParameters confirms that if two unknown _opt
- // directives appear, they both are reported.
- CreateTempFile("foo.proto",
- "syntax = \"proto2\";\n"
- "message Foo {}\n");
- Run("protocol_compiler --plug_out=TestParameter:$tmpdir "
- "--xyz_opt=foo=bar --xyz_out=$tmpdir "
- "--abc_out=$tmpdir --abc_opt=foo=bar "
- "--unknown_plug_opt=Foo "
- "--proto_path=$tmpdir foo.proto");
- ExpectErrorText("Unknown flag: --unknown_plug_opt\n");
- }
- 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();
- ExpectGeneratedWithInsertions("test_generator", "TestParameter",
- "test_generator,test_plugin", "foo.proto",
- "Foo");
- ExpectGeneratedWithInsertions("test_plugin", "TestPluginParameter",
- "test_generator,test_plugin", "foo.proto",
- "Foo");
- }
- TEST_F(CommandLineInterfaceTest, InsertWithAnnotationFixup) {
- // Check that annotation spans are updated after insertions.
- CreateTempFile("foo.proto",
- "syntax = \"proto2\";\n"
- "message MockCodeGenerator_Annotate {}\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();
- CheckGeneratedAnnotations("test_generator", "foo.proto");
- CheckGeneratedAnnotations("test_plugin", "foo.proto");
- }
- #if defined(_WIN32)
- TEST_F(CommandLineInterfaceTest, WindowsOutputPath) {
- // Test that the output path can be a Windows-style path.
- CreateTempFile("foo.proto", "syntax = \"proto2\";\n");
- Run("protocol_compiler --null_out=C:\\ "
- "--proto_path=$tmpdir foo.proto");
- ExpectNoErrors();
- ExpectNullCodeGeneratorCalled("");
- }
- TEST_F(CommandLineInterfaceTest, WindowsOutputPathAndParameter) {
- // Test that we can have a windows-style output path and a parameter.
- CreateTempFile("foo.proto", "syntax = \"proto2\";\n");
- Run("protocol_compiler --null_out=bar:C:\\ "
- "--proto_path=$tmpdir foo.proto");
- ExpectNoErrors();
- ExpectNullCodeGeneratorCalled("bar");
- }
- TEST_F(CommandLineInterfaceTest, TrailingBackslash) {
- // Test that the directories can end in backslashes. Some users claim this
- // doesn't work on their system.
- CreateTempFile("foo.proto",
- "syntax = \"proto2\";\n"
- "message Foo {}\n");
- Run("protocol_compiler --test_out=$tmpdir\\ "
- "--proto_path=$tmpdir\\ foo.proto");
- ExpectNoErrors();
- ExpectGenerated("test_generator", "", "foo.proto", "Foo");
- }
- TEST_F(CommandLineInterfaceTest, Win32ErrorMessage) {
- EXPECT_EQ("The system cannot find the file specified.\r\n",
- Subprocess::Win32ErrorMessage(ERROR_FILE_NOT_FOUND));
- }
- #endif // defined(_WIN32) || defined(__CYGWIN__)
- TEST_F(CommandLineInterfaceTest, PathLookup) {
- // Test that specifying multiple directories in the proto search path works.
- CreateTempFile("b/bar.proto",
- "syntax = \"proto2\";\n"
- "message Bar {}\n");
- CreateTempFile("a/foo.proto",
- "syntax = \"proto2\";\n"
- "import \"bar.proto\";\n"
- "message Foo {\n"
- " optional Bar a = 1;\n"
- "}\n");
- CreateTempFile("b/foo.proto", "this should not be parsed\n");
- Run("protocol_compiler --test_out=$tmpdir "
- "--proto_path=$tmpdir/a --proto_path=$tmpdir/b foo.proto");
- ExpectNoErrors();
- ExpectGenerated("test_generator", "", "foo.proto", "Foo");
- }
- TEST_F(CommandLineInterfaceTest, ColonDelimitedPath) {
- // Same as PathLookup, but we provide the proto_path in a single flag.
- CreateTempFile("b/bar.proto",
- "syntax = \"proto2\";\n"
- "message Bar {}\n");
- CreateTempFile("a/foo.proto",
- "syntax = \"proto2\";\n"
- "import \"bar.proto\";\n"
- "message Foo {\n"
- " optional Bar a = 1;\n"
- "}\n");
- CreateTempFile("b/foo.proto", "this should not be parsed\n");
- Run(strings::Substitute(
- "protocol_compiler --test_out=$$tmpdir --proto_path=$0 foo.proto",
- std::string("$tmpdir/a") + CommandLineInterface::kPathSeparator +
- "$tmpdir/b"));
- ExpectNoErrors();
- ExpectGenerated("test_generator", "", "foo.proto", "Foo");
- }
- TEST_F(CommandLineInterfaceTest, NonRootMapping) {
- // Test setting up a search path mapping a directory to a non-root location.
- CreateTempFile("foo.proto",
- "syntax = \"proto2\";\n"
- "message Foo {}\n");
- Run("protocol_compiler --test_out=$tmpdir "
- "--proto_path=bar=$tmpdir bar/foo.proto");
- ExpectNoErrors();
- ExpectGenerated("test_generator", "", "bar/foo.proto", "Foo");
- }
- TEST_F(CommandLineInterfaceTest, PathWithEqualsSign) {
- // Test setting up a search path which happens to have '=' in it.
- CreateTempDir("with=sign");
- CreateTempFile("with=sign/foo.proto",
- "syntax = \"proto2\";\n"
- "message Foo {}\n");
- Run("protocol_compiler --test_out=$tmpdir "
- "--proto_path=$tmpdir/with=sign foo.proto");
- ExpectNoErrors();
- ExpectGenerated("test_generator", "", "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.
- CreateTempFile("foo.proto",
- "syntax = \"proto2\";\n"
- "message Foo {}\n");
- // Create the "a" and "b" sub-directories.
- CreateTempDir("a");
- CreateTempDir("b");
- Run("protocol_compiler "
- "--test_out=$tmpdir/a "
- "--alt_out=$tmpdir/b "
- "--proto_path=$tmpdir foo.proto");
- ExpectNoErrors();
- 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.
- CreateTempFile("foo.proto",
- "syntax = \"proto2\";\n"
- "message Foo {}\n");
- Run("protocol_compiler --disallow_services --test_out=$tmpdir "
- "--proto_path=$tmpdir foo.proto");
- ExpectNoErrors();
- ExpectGenerated("test_generator", "", "foo.proto", "Foo");
- }
- TEST_F(CommandLineInterfaceTest, DisallowServicesHasService) {
- // Test that --disallow_services produces an error when there are services.
- CreateTempFile("foo.proto",
- "syntax = \"proto2\";\n"
- "message Foo {}\n"
- "service Bar {}\n");
- Run("protocol_compiler --disallow_services --test_out=$tmpdir "
- "--proto_path=$tmpdir foo.proto");
- ExpectErrorSubstring("foo.proto: This file contains services");
- }
- TEST_F(CommandLineInterfaceTest, AllowServicesHasService) {
- // Test that services work fine as long as --disallow_services is not used.
- CreateTempFile("foo.proto",
- "syntax = \"proto2\";\n"
- "message Foo {}\n"
- "service Bar {}\n");
- Run("protocol_compiler --test_out=$tmpdir "
- "--proto_path=$tmpdir foo.proto");
- ExpectNoErrors();
- ExpectGenerated("test_generator", "", "foo.proto", "Foo");
- }
- TEST_F(CommandLineInterfaceTest, DirectDependencies_Missing_EmptyList) {
- CreateTempFile("foo.proto",
- "syntax = \"proto2\";\n"
- "import \"bar.proto\";\n"
- "message Foo { optional Bar bar = 1; }");
- CreateTempFile("bar.proto",
- "syntax = \"proto2\";\n"
- "message Bar { optional string text = 1; }");
- Run("protocol_compiler --test_out=$tmpdir --proto_path=$tmpdir "
- "--direct_dependencies= foo.proto");
- ExpectErrorText(
- "foo.proto: File is imported but not declared in --direct_dependencies: "
- "bar.proto\n");
- }
- TEST_F(CommandLineInterfaceTest, DirectDependencies_Missing) {
- CreateTempFile("foo.proto",
- "syntax = \"proto2\";\n"
- "import \"bar.proto\";\n"
- "import \"bla.proto\";\n"
- "message Foo { optional Bar bar = 1; optional Bla bla = 2; }");
- CreateTempFile("bar.proto",
- "syntax = \"proto2\";\n"
- "message Bar { optional string text = 1; }");
- CreateTempFile("bla.proto",
- "syntax = \"proto2\";\n"
- "message Bla { optional int64 number = 1; }");
- Run("protocol_compiler --test_out=$tmpdir --proto_path=$tmpdir "
- "--direct_dependencies=bla.proto foo.proto");
- ExpectErrorText(
- "foo.proto: File is imported but not declared in --direct_dependencies: "
- "bar.proto\n");
- }
- TEST_F(CommandLineInterfaceTest, DirectDependencies_NoViolation) {
- CreateTempFile("foo.proto",
- "syntax = \"proto2\";\n"
- "import \"bar.proto\";\n"
- "message Foo { optional Bar bar = 1; }");
- CreateTempFile("bar.proto",
- "syntax = \"proto2\";\n"
- "message Bar { optional string text = 1; }");
- Run("protocol_compiler --test_out=$tmpdir --proto_path=$tmpdir "
- "--direct_dependencies=bar.proto foo.proto");
- ExpectNoErrors();
- }
- TEST_F(CommandLineInterfaceTest, DirectDependencies_NoViolation_MultiImports) {
- CreateTempFile("foo.proto",
- "syntax = \"proto2\";\n"
- "import \"bar.proto\";\n"
- "import \"bla.proto\";\n"
- "message Foo { optional Bar bar = 1; optional Bla bla = 2; }");
- CreateTempFile("bar.proto",
- "syntax = \"proto2\";\n"
- "message Bar { optional string text = 1; }");
- CreateTempFile("bla.proto",
- "syntax = \"proto2\";\n"
- "message Bla { optional int64 number = 1; }");
- Run("protocol_compiler --test_out=$tmpdir --proto_path=$tmpdir "
- "--direct_dependencies=bar.proto:bla.proto foo.proto");
- ExpectNoErrors();
- }
- TEST_F(CommandLineInterfaceTest, DirectDependencies_ProvidedMultipleTimes) {
- CreateTempFile("foo.proto", "syntax = \"proto2\";\n");
- Run("protocol_compiler --test_out=$tmpdir --proto_path=$tmpdir "
- "--direct_dependencies=bar.proto --direct_dependencies=bla.proto "
- "foo.proto");
- ExpectErrorText(
- "--direct_dependencies may only be passed once. To specify multiple "
- "direct dependencies, pass them all as a single parameter separated by "
- "':'.\n");
- }
- TEST_F(CommandLineInterfaceTest, DirectDependencies_CustomErrorMessage) {
- CreateTempFile("foo.proto",
- "syntax = \"proto2\";\n"
- "import \"bar.proto\";\n"
- "message Foo { optional Bar bar = 1; }");
- CreateTempFile("bar.proto",
- "syntax = \"proto2\";\n"
- "message Bar { optional string text = 1; }");
- std::vector<std::string> commands;
- commands.push_back("protocol_compiler");
- commands.push_back("--test_out=$tmpdir");
- commands.push_back("--proto_path=$tmpdir");
- commands.push_back("--direct_dependencies=");
- commands.push_back("--direct_dependencies_violation_msg=Bla \"%s\" Bla");
- commands.push_back("foo.proto");
- RunWithArgs(commands);
- ExpectErrorText("foo.proto: Bla \"bar.proto\" Bla\n");
- }
- TEST_F(CommandLineInterfaceTest, CwdRelativeInputs) {
- // Test that we can accept working-directory-relative input files.
- CreateTempFile("foo.proto",
- "syntax = \"proto2\";\n"
- "message Foo {}\n");
- Run("protocol_compiler --test_out=$tmpdir "
- "--proto_path=$tmpdir $tmpdir/foo.proto");
- ExpectNoErrors();
- ExpectGenerated("test_generator", "", "foo.proto", "Foo");
- }
- TEST_F(CommandLineInterfaceTest, WriteDescriptorSet) {
- CreateTempFile("foo.proto",
- "syntax = \"proto2\";\n"
- "message Foo {}\n");
- CreateTempFile("bar.proto",
- "syntax = \"proto2\";\n"
- "import \"foo.proto\";\n"
- "message Bar {\n"
- " optional Foo foo = 1;\n"
- "}\n");
- Run("protocol_compiler --descriptor_set_out=$tmpdir/descriptor_set "
- "--proto_path=$tmpdir bar.proto");
- ExpectNoErrors();
- FileDescriptorSet descriptor_set;
- ReadDescriptorSet("descriptor_set", &descriptor_set);
- if (HasFatalFailure()) return;
- EXPECT_EQ(1, descriptor_set.file_size());
- EXPECT_EQ("bar.proto", descriptor_set.file(0).name());
- // Descriptor set should not have source code info.
- EXPECT_FALSE(descriptor_set.file(0).has_source_code_info());
- // Descriptor set should have json_name.
- EXPECT_EQ("Bar", descriptor_set.file(0).message_type(0).name());
- EXPECT_EQ("foo", descriptor_set.file(0).message_type(0).field(0).name());
- EXPECT_TRUE(descriptor_set.file(0).message_type(0).field(0).has_json_name());
- }
- TEST_F(CommandLineInterfaceTest, WriteDescriptorSetWithDuplicates) {
- CreateTempFile("foo.proto",
- "syntax = \"proto2\";\n"
- "message Foo {}\n");
- CreateTempFile("bar.proto",
- "syntax = \"proto2\";\n"
- "import \"foo.proto\";\n"
- "message Bar {\n"
- " optional Foo foo = 1;\n"
- "}\n");
- CreateTempFile("baz.proto",
- "syntax = \"proto2\";\n"
- "import \"foo.proto\";\n"
- "message Baz {\n"
- " optional Foo foo = 1;\n"
- "}\n");
- Run("protocol_compiler --descriptor_set_out=$tmpdir/descriptor_set "
- "--proto_path=$tmpdir bar.proto foo.proto bar.proto baz.proto");
- ExpectNoErrors();
- FileDescriptorSet descriptor_set;
- ReadDescriptorSet("descriptor_set", &descriptor_set);
- if (HasFatalFailure()) return;
- EXPECT_EQ(3, descriptor_set.file_size());
- // foo should come first since the output is in dependency order.
- // since bar and baz are unordered, they should be in command line order.
- EXPECT_EQ("foo.proto", descriptor_set.file(0).name());
- EXPECT_EQ("bar.proto", descriptor_set.file(1).name());
- EXPECT_EQ("baz.proto", descriptor_set.file(2).name());
- // Descriptor set should not have source code info.
- EXPECT_FALSE(descriptor_set.file(0).has_source_code_info());
- // Descriptor set should have json_name.
- EXPECT_EQ("Bar", descriptor_set.file(1).message_type(0).name());
- EXPECT_EQ("foo", descriptor_set.file(1).message_type(0).field(0).name());
- EXPECT_TRUE(descriptor_set.file(1).message_type(0).field(0).has_json_name());
- }
- TEST_F(CommandLineInterfaceTest, WriteDescriptorSetWithSourceInfo) {
- CreateTempFile("foo.proto",
- "syntax = \"proto2\";\n"
- "message Foo {}\n");
- CreateTempFile("bar.proto",
- "syntax = \"proto2\";\n"
- "import \"foo.proto\";\n"
- "message Bar {\n"
- " optional Foo foo = 1;\n"
- "}\n");
- Run("protocol_compiler --descriptor_set_out=$tmpdir/descriptor_set "
- "--include_source_info --proto_path=$tmpdir bar.proto");
- ExpectNoErrors();
- FileDescriptorSet descriptor_set;
- ReadDescriptorSet("descriptor_set", &descriptor_set);
- if (HasFatalFailure()) return;
- EXPECT_EQ(1, descriptor_set.file_size());
- EXPECT_EQ("bar.proto", descriptor_set.file(0).name());
- // Source code info included.
- EXPECT_TRUE(descriptor_set.file(0).has_source_code_info());
- }
- TEST_F(CommandLineInterfaceTest, WriteTransitiveDescriptorSet) {
- CreateTempFile("foo.proto",
- "syntax = \"proto2\";\n"
- "message Foo {}\n");
- CreateTempFile("bar.proto",
- "syntax = \"proto2\";\n"
- "import \"foo.proto\";\n"
- "message Bar {\n"
- " optional Foo foo = 1;\n"
- "}\n");
- Run("protocol_compiler --descriptor_set_out=$tmpdir/descriptor_set "
- "--include_imports --proto_path=$tmpdir bar.proto");
- ExpectNoErrors();
- FileDescriptorSet descriptor_set;
- ReadDescriptorSet("descriptor_set", &descriptor_set);
- if (HasFatalFailure()) return;
- EXPECT_EQ(2, descriptor_set.file_size());
- if (descriptor_set.file(0).name() == "bar.proto") {
- std::swap(descriptor_set.mutable_file()->mutable_data()[0],
- descriptor_set.mutable_file()->mutable_data()[1]);
- }
- EXPECT_EQ("foo.proto", descriptor_set.file(0).name());
- EXPECT_EQ("bar.proto", descriptor_set.file(1).name());
- // Descriptor set should not have source code info.
- EXPECT_FALSE(descriptor_set.file(0).has_source_code_info());
- EXPECT_FALSE(descriptor_set.file(1).has_source_code_info());
- }
- TEST_F(CommandLineInterfaceTest, WriteTransitiveDescriptorSetWithSourceInfo) {
- CreateTempFile("foo.proto",
- "syntax = \"proto2\";\n"
- "message Foo {}\n");
- CreateTempFile("bar.proto",
- "syntax = \"proto2\";\n"
- "import \"foo.proto\";\n"
- "message Bar {\n"
- " optional Foo foo = 1;\n"
- "}\n");
- Run("protocol_compiler --descriptor_set_out=$tmpdir/descriptor_set "
- "--include_imports --include_source_info --proto_path=$tmpdir bar.proto");
- ExpectNoErrors();
- FileDescriptorSet descriptor_set;
- ReadDescriptorSet("descriptor_set", &descriptor_set);
- if (HasFatalFailure()) return;
- EXPECT_EQ(2, descriptor_set.file_size());
- if (descriptor_set.file(0).name() == "bar.proto") {
- std::swap(descriptor_set.mutable_file()->mutable_data()[0],
- descriptor_set.mutable_file()->mutable_data()[1]);
- }
- EXPECT_EQ("foo.proto", descriptor_set.file(0).name());
- EXPECT_EQ("bar.proto", descriptor_set.file(1).name());
- // Source code info included.
- EXPECT_TRUE(descriptor_set.file(0).has_source_code_info());
- EXPECT_TRUE(descriptor_set.file(1).has_source_code_info());
- }
- #ifdef _WIN32
- // TODO(teboring): Figure out how to write test on windows.
- #else
- TEST_F(CommandLineInterfaceTest, WriteDependencyManifestFileGivenTwoInputs) {
- CreateTempFile("foo.proto",
- "syntax = \"proto2\";\n"
- "message Foo {}\n");
- CreateTempFile("bar.proto",
- "syntax = \"proto2\";\n"
- "import \"foo.proto\";\n"
- "message Bar {\n"
- " optional Foo foo = 1;\n"
- "}\n");
- Run("protocol_compiler --dependency_out=$tmpdir/manifest "
- "--test_out=$tmpdir --proto_path=$tmpdir bar.proto foo.proto");
- ExpectErrorText(
- "Can only process one input file when using --dependency_out=FILE.\n");
- }
- #ifdef PROTOBUF_OPENSOURCE
- TEST_F(CommandLineInterfaceTest, WriteDependencyManifestFile) {
- CreateTempFile("foo.proto",
- "syntax = \"proto2\";\n"
- "message Foo {}\n");
- CreateTempFile("bar.proto",
- "syntax = \"proto2\";\n"
- "import \"foo.proto\";\n"
- "message Bar {\n"
- " optional Foo foo = 1;\n"
- "}\n");
- std::string current_working_directory = getcwd(NULL, 0);
- SwitchToTempDirectory();
- Run("protocol_compiler --dependency_out=manifest --test_out=. "
- "bar.proto");
- ExpectNoErrors();
- ExpectFileContent("manifest",
- "bar.proto.MockCodeGenerator.test_generator: "
- "foo.proto\\\n bar.proto");
- File::ChangeWorkingDirectory(current_working_directory);
- }
- #else // !PROTOBUF_OPENSOURCE
- // TODO(teboring): Figure out how to change and get working directory in
- // google3.
- #endif // !PROTOBUF_OPENSOURCE
- TEST_F(CommandLineInterfaceTest, WriteDependencyManifestFileForAbsolutePath) {
- CreateTempFile("foo.proto",
- "syntax = \"proto2\";\n"
- "message Foo {}\n");
- CreateTempFile("bar.proto",
- "syntax = \"proto2\";\n"
- "import \"foo.proto\";\n"
- "message Bar {\n"
- " optional Foo foo = 1;\n"
- "}\n");
- Run("protocol_compiler --dependency_out=$tmpdir/manifest "
- "--test_out=$tmpdir --proto_path=$tmpdir bar.proto");
- ExpectNoErrors();
- ExpectFileContent("manifest",
- "$tmpdir/bar.proto.MockCodeGenerator.test_generator: "
- "$tmpdir/foo.proto\\\n $tmpdir/bar.proto");
- }
- #endif // !_WIN32
- TEST_F(CommandLineInterfaceTest, TestArgumentFile) {
- // Test parsing multiple input files using an argument file.
- CreateTempFile("foo.proto",
- "syntax = \"proto2\";\n"
- "message Foo {}\n");
- CreateTempFile("bar.proto",
- "syntax = \"proto2\";\n"
- "message Bar {}\n");
- CreateTempFile("arguments.txt",
- "--test_out=$tmpdir\n"
- "--plug_out=$tmpdir\n"
- "--proto_path=$tmpdir\n"
- "--direct_dependencies_violation_msg=%s is not imported\n"
- "foo.proto\n"
- "bar.proto");
- Run("protocol_compiler @$tmpdir/arguments.txt");
- ExpectNoErrors();
- ExpectGeneratedWithMultipleInputs("test_generator", "foo.proto,bar.proto",
- "foo.proto", "Foo");
- ExpectGeneratedWithMultipleInputs("test_generator", "foo.proto,bar.proto",
- "bar.proto", "Bar");
- ExpectGeneratedWithMultipleInputs("test_plugin", "foo.proto,bar.proto",
- "foo.proto", "Foo");
- ExpectGeneratedWithMultipleInputs("test_plugin", "foo.proto,bar.proto",
- "bar.proto", "Bar");
- }
- // -------------------------------------------------------------------
- TEST_F(CommandLineInterfaceTest, ParseErrors) {
- // Test that parse errors are reported.
- CreateTempFile("foo.proto",
- "syntax = \"proto2\";\n"
- "badsyntax\n");
- Run("protocol_compiler --test_out=$tmpdir "
- "--proto_path=$tmpdir foo.proto");
- ExpectErrorText(
- "foo.proto:2:1: Expected top-level statement (e.g. \"message\").\n");
- }
- TEST_F(CommandLineInterfaceTest, ParseErrors_DescriptorSetIn) {
- // Test that parse errors are reported.
- CreateTempFile("foo.bin", "not a FileDescriptorSet");
- Run("protocol_compiler --test_out=$tmpdir "
- "--descriptor_set_in=$tmpdir/foo.bin foo.proto");
- ExpectErrorText("$tmpdir/foo.bin: Unable to parse.\n");
- }
- TEST_F(CommandLineInterfaceTest, ParseErrorsMultipleFiles) {
- // Test that parse errors are reported from multiple files.
- // 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.
- CreateTempFile("bar.proto",
- "syntax = \"proto2\";\n"
- "badsyntax\n");
- CreateTempFile("baz.proto",
- "syntax = \"proto2\";\n"
- "import \"bar.proto\";\n");
- CreateTempFile("foo.proto",
- "syntax = \"proto2\";\n"
- "import \"bar.proto\";\n"
- "import \"baz.proto\";\n");
- Run("protocol_compiler --test_out=$tmpdir "
- "--proto_path=$tmpdir foo.proto");
- ExpectErrorText(
- "bar.proto:2:1: Expected top-level statement (e.g. \"message\").\n"
- "baz.proto:2:1: Import \"bar.proto\" was not found or had errors.\n"
- "foo.proto:2:1: Import \"bar.proto\" was not found or had errors.\n"
- "foo.proto:3:1: Import \"baz.proto\" was not found or had errors.\n");
- }
- TEST_F(CommandLineInterfaceTest, RecursiveImportFails) {
- // Create a proto file that imports itself.
- CreateTempFile("foo.proto",
- "syntax = \"proto2\";\n"
- "import \"foo.proto\";\n");
- Run("protocol_compiler --test_out=$tmpdir "
- "--proto_path=$tmpdir foo.proto");
- ExpectErrorSubstring(
- "foo.proto:2:1: File recursively imports itself: "
- "foo.proto -> foo.proto\n");
- }
- TEST_F(CommandLineInterfaceTest, InputNotFoundError) {
- // Test what happens if the input file is not found.
- Run("protocol_compiler --test_out=$tmpdir "
- "--proto_path=$tmpdir foo.proto");
- ExpectErrorText("foo.proto: No such file or directory\n");
- }
- TEST_F(CommandLineInterfaceTest, InputNotFoundError_DescriptorSetIn) {
- // Test what happens if the input file is not found.
- Run("protocol_compiler --test_out=$tmpdir "
- "--descriptor_set_in=$tmpdir/foo.bin foo.proto");
- ExpectErrorText("$tmpdir/foo.bin: No such file or directory\n");
- }
- TEST_F(CommandLineInterfaceTest, CwdRelativeInputNotFoundError) {
- // Test what happens when a working-directory-relative input file is not
- // found.
- Run("protocol_compiler --test_out=$tmpdir "
- "--proto_path=$tmpdir $tmpdir/foo.proto");
- ExpectErrorText("$tmpdir/foo.proto: No such file or directory\n");
- }
- TEST_F(CommandLineInterfaceTest, CwdRelativeInputNotMappedError) {
- // Test what happens when a working-directory-relative input file is not
- // mapped to a virtual path.
- CreateTempFile("foo.proto",
- "syntax = \"proto2\";\n"
- "message Foo {}\n");
- // Create a directory called "bar" so that we can point --proto_path at it.
- CreateTempFile("bar/dummy", "");
- Run("protocol_compiler --test_out=$tmpdir "
- "--proto_path=$tmpdir/bar $tmpdir/foo.proto");
- ExpectErrorText(
- "$tmpdir/foo.proto: File does not reside within any path "
- "specified using --proto_path (or -I). You must specify a "
- "--proto_path which encompasses this file. Note that the "
- "proto_path must be an exact prefix of the .proto file "
- "names -- protoc is too dumb to figure out when two paths "
- "(e.g. absolute and relative) are equivalent (it's harder "
- "than you think).\n");
- }
- TEST_F(CommandLineInterfaceTest, CwdRelativeInputNotFoundAndNotMappedError) {
- // Check what happens if the input file is not found *and* is not mapped
- // in the proto_path.
- // Create a directory called "bar" so that we can point --proto_path at it.
- CreateTempFile("bar/dummy", "");
- Run("protocol_compiler --test_out=$tmpdir "
- "--proto_path=$tmpdir/bar $tmpdir/foo.proto");
- ExpectErrorText("$tmpdir/foo.proto: No such file or directory\n");
- }
- TEST_F(CommandLineInterfaceTest, CwdRelativeInputShadowedError) {
- // Test what happens when a working-directory-relative input file is shadowed
- // by another file in the virtual path.
- CreateTempFile("foo/foo.proto",
- "syntax = \"proto2\";\n"
- "message Foo {}\n");
- CreateTempFile("bar/foo.proto",
- "syntax = \"proto2\";\n"
- "message Bar {}\n");
- Run("protocol_compiler --test_out=$tmpdir "
- "--proto_path=$tmpdir/foo --proto_path=$tmpdir/bar "
- "$tmpdir/bar/foo.proto");
- ExpectErrorText(
- "$tmpdir/bar/foo.proto: Input is shadowed in the --proto_path "
- "by \"$tmpdir/foo/foo.proto\". Either use the latter "
- "file as your input or reorder the --proto_path so that the "
- "former file's location comes first.\n");
- }
- TEST_F(CommandLineInterfaceTest, ProtoPathNotFoundError) {
- // Test what happens if the input file is not found.
- Run("protocol_compiler --test_out=$tmpdir "
- "--proto_path=$tmpdir/foo foo.proto");
- ExpectErrorText(
- "$tmpdir/foo: warning: directory does not exist.\n"
- "foo.proto: No such file or directory\n");
- }
- TEST_F(CommandLineInterfaceTest, ProtoPathAndDescriptorSetIn) {
- Run("protocol_compiler --test_out=$tmpdir "
- "--proto_path=$tmpdir --descriptor_set_in=$tmpdir/foo.bin foo.proto");
- ExpectErrorText("$tmpdir/foo.bin: No such file or directory\n");
- Run("protocol_compiler --test_out=$tmpdir "
- "--descriptor_set_in=$tmpdir/foo.bin --proto_path=$tmpdir foo.proto");
- ExpectErrorText("$tmpdir/foo.bin: No such file or directory\n");
- }
- TEST_F(CommandLineInterfaceTest, ProtoPathAndDescriptorSetIn_CompileFiles) {
- // Test what happens if a proto is in a --descriptor_set_in and also exists
- // on disk.
- FileDescriptorSet file_descriptor_set;
- // NOTE: This file desc SHOULD be different from the one created as a temp
- // to make it easier to test that the file was output instead of the
- // contents of the --descriptor_set_in file.
- FileDescriptorProto* file_descriptor_proto = file_descriptor_set.add_file();
- file_descriptor_proto->set_name("foo.proto");
- file_descriptor_proto->add_message_type()->set_name("Foo");
- WriteDescriptorSet("foo.bin", &file_descriptor_set);
- CreateTempFile("foo.proto",
- "syntax = \"proto2\";\n"
- "message FooBar { required string foo_message = 1; }\n");
- Run("protocol_compiler --descriptor_set_out=$tmpdir/descriptor_set "
- "--descriptor_set_in=$tmpdir/foo.bin "
- "--include_source_info "
- "--proto_path=$tmpdir foo.proto");
- ExpectNoErrors();
- FileDescriptorSet descriptor_set;
- ReadDescriptorSet("descriptor_set", &descriptor_set);
- EXPECT_EQ(1, descriptor_set.file_size());
- EXPECT_EQ("foo.proto", descriptor_set.file(0).name());
- // Descriptor set SHOULD have source code info.
- EXPECT_TRUE(descriptor_set.file(0).has_source_code_info());
- EXPECT_EQ("FooBar", descriptor_set.file(0).message_type(0).name());
- EXPECT_EQ("foo_message",
- descriptor_set.file(0).message_type(0).field(0).name());
- }
- TEST_F(CommandLineInterfaceTest, ProtoPathAndDependencyOut) {
- Run("protocol_compiler --test_out=$tmpdir "
- "--dependency_out=$tmpdir/manifest "
- "--descriptor_set_in=$tmpdir/foo.bin foo.proto");
- ExpectErrorText(
- "--descriptor_set_in cannot be used with --dependency_out.\n");
- Run("protocol_compiler --test_out=$tmpdir "
- "--descriptor_set_in=$tmpdir/foo.bin "
- "--dependency_out=$tmpdir/manifest foo.proto");
- ExpectErrorText(
- "--dependency_out cannot be used with --descriptor_set_in.\n");
- }
- TEST_F(CommandLineInterfaceTest, MissingInputError) {
- // Test that we get an error if no inputs are given.
- Run("protocol_compiler --test_out=$tmpdir "
- "--proto_path=$tmpdir");
- ExpectErrorText("Missing input file.\n");
- }
- TEST_F(CommandLineInterfaceTest, MissingOutputError) {
- CreateTempFile("foo.proto",
- "syntax = \"proto2\";\n"
- "message Foo {}\n");
- Run("protocol_compiler --proto_path=$tmpdir foo.proto");
- ExpectErrorText("Missing output directives.\n");
- }
- TEST_F(CommandLineInterfaceTest, OutputWriteError) {
- CreateTempFile("foo.proto",
- "syntax = \"proto2\";\n"
- "message Foo {}\n");
- std::string output_file =
- MockCodeGenerator::GetOutputFileName("test_generator", "foo.proto");
- // Create a directory blocking our output location.
- CreateTempDir(output_file);
- Run("protocol_compiler --test_out=$tmpdir "
- "--proto_path=$tmpdir foo.proto");
- // MockCodeGenerator no longer detects an error because we actually write to
- // an in-memory location first, then dump to disk at the end. This is no
- // big deal.
- // ExpectErrorSubstring("MockCodeGenerator detected write error.");
- #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, PluginOutputWriteError) {
- CreateTempFile("foo.proto",
- "syntax = \"proto2\";\n"
- "message Foo {}\n");
- std::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");
- Run("protocol_compiler --test_out=$tmpdir/nosuchdir "
- "--proto_path=$tmpdir foo.proto");
- ExpectErrorSubstring("nosuchdir/: No such file or directory");
- }
- 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");
- Run("protocol_compiler --test_out=$tmpdir/foo.proto "
- "--proto_path=$tmpdir foo.proto");
- #if defined(_WIN32) && !defined(__CYGWIN__)
- // Windows with MSVCRT.dll produces EINVAL instead of ENOTDIR.
- if (HasAlternateErrorSubstring("foo.proto/: Invalid argument")) {
- return;
- }
- #endif
- ExpectErrorSubstring("foo.proto/: Not a directory");
- }
- TEST_F(CommandLineInterfaceTest, GeneratorError) {
- 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 MockCodeGenerator_Error {}\n");
- Run("protocol_compiler --plug_out=TestParameter:$tmpdir "
- "--proto_path=$tmpdir foo.proto");
- ExpectErrorSubstring(
- "--plug_out: foo.proto: Saw message type MockCodeGenerator_Error.");
- }
- 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.");
- #ifdef _WIN32
- // Windows doesn't have signals. It looks like abort()ing causes the process
- // to exit with status code 3, but let's not depend on the exact number here.
- ExpectErrorSubstring(
- "--plug_out: prefix-gen-plug: Plugin failed with status code");
- #else
- // Don't depend on the exact signal number.
- ExpectErrorSubstring("--plug_out: prefix-gen-plug: Plugin killed by signal");
- #endif
- }
- TEST_F(CommandLineInterfaceTest, PluginReceivesSourceCodeInfo) {
- CreateTempFile("foo.proto",
- "syntax = \"proto2\";\n"
- "message MockCodeGenerator_HasSourceCodeInfo {}\n");
- Run("protocol_compiler --plug_out=$tmpdir --proto_path=$tmpdir foo.proto");
- ExpectErrorSubstring(
- "Saw message type MockCodeGenerator_HasSourceCodeInfo: 1.");
- }
- TEST_F(CommandLineInterfaceTest, PluginReceivesJsonName) {
- CreateTempFile("foo.proto",
- "syntax = \"proto2\";\n"
- "message MockCodeGenerator_HasJsonName {\n"
- " optional int32 value = 1;\n"
- "}\n");
- Run("protocol_compiler --plug_out=$tmpdir --proto_path=$tmpdir foo.proto");
- ExpectErrorSubstring("Saw json_name: 1");
- }
- TEST_F(CommandLineInterfaceTest, PluginReceivesCompilerVersion) {
- CreateTempFile("foo.proto",
- "syntax = \"proto2\";\n"
- "message MockCodeGenerator_ShowVersionNumber {\n"
- " optional int32 value = 1;\n"
- "}\n");
- Run("protocol_compiler --plug_out=$tmpdir --proto_path=$tmpdir foo.proto");
- ExpectErrorSubstring(StringPrintf("Saw compiler_version: %d %s",
- GOOGLE_PROTOBUF_VERSION,
- GOOGLE_PROTOBUF_VERSION_SUFFIX));
- }
- 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");
- #ifdef _WIN32
- ExpectErrorSubstring("--badplug_out: prefix-gen-badplug: " +
- Subprocess::Win32ErrorMessage(ERROR_FILE_NOT_FOUND));
- #else
- // Error written to stdout by child process after exec() fails.
- ExpectErrorSubstring("no_such_file: program not found or is not executable");
- ExpectErrorSubstring(
- "Please specify a program using absolute path or make sure "
- "the program is available in your PATH system variable");
- // Error written by parent process when child fails.
- ExpectErrorSubstring(
- "--badplug_out: prefix-gen-badplug: Plugin failed with status code 1.");
- #endif
- }
- 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");
- ExpectCapturedStdoutSubstringWithZeroReturnCode("Usage: test_exec_name ");
- ExpectCapturedStdoutSubstringWithZeroReturnCode("--test_out=OUT_DIR");
- ExpectCapturedStdoutSubstringWithZeroReturnCode("Test output.");
- ExpectCapturedStdoutSubstringWithZeroReturnCode("--alt_out=OUT_DIR");
- ExpectCapturedStdoutSubstringWithZeroReturnCode("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).
- CreateTempFile("foo.proto",
- "syntax = \"proto2\";\n"
- "badsyntax\n");
- Run("protocol_compiler --test_out=$tmpdir "
- "--proto_path=$tmpdir --error_format=gcc foo.proto");
- ExpectErrorText(
- "foo.proto:2:1: Expected top-level statement (e.g. \"message\").\n");
- }
- TEST_F(CommandLineInterfaceTest, MsvsFormatErrors) {
- // Test --error_format=msvs
- CreateTempFile("foo.proto",
- "syntax = \"proto2\";\n"
- "badsyntax\n");
- Run("protocol_compiler --test_out=$tmpdir "
- "--proto_path=$tmpdir --error_format=msvs foo.proto");
- ExpectErrorText(
- "$tmpdir/foo.proto(2) : error in column=1: Expected top-level statement "
- "(e.g. \"message\").\n");
- }
- TEST_F(CommandLineInterfaceTest, InvalidErrorFormat) {
- // Test --error_format=msvs
- CreateTempFile("foo.proto",
- "syntax = \"proto2\";\n"
- "badsyntax\n");
- Run("protocol_compiler --test_out=$tmpdir "
- "--proto_path=$tmpdir --error_format=invalid foo.proto");
- ExpectErrorText("Unknown error format: invalid\n");
- }
- // -------------------------------------------------------------------
- // Flag parsing tests
- TEST_F(CommandLineInterfaceTest, ParseSingleCharacterFlag) {
- // Test that a single-character flag works.
- CreateTempFile("foo.proto",
- "syntax = \"proto2\";\n"
- "message Foo {}\n");
- Run("protocol_compiler -t$tmpdir "
- "--proto_path=$tmpdir foo.proto");
- ExpectNoErrors();
- ExpectGenerated("test_generator", "", "foo.proto", "Foo");
- }
- TEST_F(CommandLineInterfaceTest, ParseSpaceDelimitedValue) {
- // Test that separating the flag value with a space works.
- CreateTempFile("foo.proto",
- "syntax = \"proto2\";\n"
- "message Foo {}\n");
- Run("protocol_compiler --test_out $tmpdir "
- "--proto_path=$tmpdir foo.proto");
- ExpectNoErrors();
- ExpectGenerated("test_generator", "", "foo.proto", "Foo");
- }
- TEST_F(CommandLineInterfaceTest, ParseSingleCharacterSpaceDelimitedValue) {
- // Test that separating the flag value with a space works for
- // single-character flags.
- CreateTempFile("foo.proto",
- "syntax = \"proto2\";\n"
- "message Foo {}\n");
- Run("protocol_compiler -t $tmpdir "
- "--proto_path=$tmpdir foo.proto");
- ExpectNoErrors();
- ExpectGenerated("test_generator", "", "foo.proto", "Foo");
- }
- TEST_F(CommandLineInterfaceTest, MissingValueError) {
- // Test that we get an error if a flag is missing its value.
- Run("protocol_compiler --test_out --proto_path=$tmpdir foo.proto");
- ExpectErrorText("Missing value for flag: --test_out\n");
- }
- TEST_F(CommandLineInterfaceTest, MissingValueAtEndError) {
- // Test that we get an error if the last argument is a flag requiring a
- // value.
- Run("protocol_compiler --test_out");
- ExpectErrorText("Missing value for flag: --test_out\n");
- }
- TEST_F(CommandLineInterfaceTest, PrintFreeFieldNumbers) {
- CreateTempFile("foo.proto",
- "syntax = \"proto2\";\n"
- "package foo;\n"
- "message Foo {\n"
- " optional int32 a = 2;\n"
- " optional string b = 4;\n"
- " optional string c = 5;\n"
- " optional int64 d = 8;\n"
- " optional double e = 10;\n"
- "}\n");
- CreateTempFile("bar.proto",
- "syntax = \"proto2\";\n"
- "message Bar {\n"
- " optional int32 a = 2;\n"
- " extensions 4 to 5;\n"
- " optional int64 d = 8;\n"
- " extensions 10;\n"
- "}\n");
- CreateTempFile("baz.proto",
- "syntax = \"proto2\";\n"
- "message Baz {\n"
- " optional int32 a = 2;\n"
- " optional int64 d = 8;\n"
- " extensions 15 to max;\n" // unordered.
- " extensions 13;\n"
- " extensions 10 to 12;\n"
- " extensions 5;\n"
- " extensions 4;\n"
- "}\n");
- CreateTempFile(
- "quz.proto",
- "syntax = \"proto2\";\n"
- "message Quz {\n"
- " message Foo {}\n" // nested message
- " optional int32 a = 2;\n"
- " optional group C = 4 {\n"
- " optional int32 d = 5;\n"
- " }\n"
- " extensions 8 to 10;\n"
- " optional group E = 11 {\n"
- " optional int32 f = 9;\n" // explicitly reuse extension range 8-10
- " optional group G = 15 {\n" // nested group
- " message Foo {}\n" // nested message inside nested group
- " }\n"
- " }\n"
- "}\n");
- Run("protocol_compiler --print_free_field_numbers --proto_path=$tmpdir "
- "foo.proto bar.proto baz.proto quz.proto");
- ExpectNoErrors();
- // TODO(jieluo): Cygwin doesn't work well if we try to capture stderr and
- // stdout at the same time. Need to figure out why and add this test back
- // for Cygwin.
- #if !defined(__CYGWIN__)
- ExpectCapturedStdout(
- "foo.Foo free: 1 3 6-7 9 11-INF\n"
- "Bar free: 1 3 6-7 9 11-INF\n"
- "Baz free: 1 3 6-7 9 14\n"
- "Quz.Foo free: 1-INF\n"
- "Quz.E.G.Foo free: 1-INF\n"
- "Quz free: 1 3 6-7 12-14 16-INF\n");
- #endif
- }
- // ===================================================================
- // Test for --encode and --decode. Note that it would be easier to do this
- // test as a shell script, but we'd like to be able to run the test on
- // platforms that don't have a Bourne-compatible shell available (especially
- // Windows/MSVC).
- enum EncodeDecodeTestMode { PROTO_PATH, DESCRIPTOR_SET_IN };
- class EncodeDecodeTest : public testing::TestWithParam<EncodeDecodeTestMode> {
- protected:
- virtual void SetUp() {
- WriteUnittestProtoDescriptorSet();
- duped_stdin_ = dup(STDIN_FILENO);
- }
- virtual void TearDown() {
- dup2(duped_stdin_, STDIN_FILENO);
- close(duped_stdin_);
- }
- void RedirectStdinFromText(const std::string& input) {
- std::string filename = TestTempDir() + "/test_stdin";
- GOOGLE_CHECK_OK(File::SetContents(filename, input, true));
- GOOGLE_CHECK(RedirectStdinFromFile(filename));
- }
- bool RedirectStdinFromFile(const std::string& filename) {
- int fd = open(filename.c_str(), O_RDONLY);
- if (fd < 0) return false;
- dup2(fd, STDIN_FILENO);
- close(fd);
- return true;
- }
- // Remove '\r' characters from text.
- std::string StripCR(const std::string& text) {
- std::string result;
- for (int i = 0; i < text.size(); i++) {
- if (text[i] != '\r') {
- result.push_back(text[i]);
- }
- }
- return result;
- }
- enum Type { TEXT, BINARY };
- enum ReturnCode { SUCCESS, ERROR };
- bool Run(const std::string& command) {
- std::vector<std::string> args;
- args.push_back("protoc");
- SplitStringUsing(command, " ", &args);
- switch (GetParam()) {
- case PROTO_PATH:
- args.push_back("--proto_path=" + TestUtil::TestSourceDir());
- break;
- case DESCRIPTOR_SET_IN:
- args.push_back(StrCat("--descriptor_set_in=",
- unittest_proto_descriptor_set_filename_));
- break;
- default:
- ADD_FAILURE() << "unexpected EncodeDecodeTestMode: " << GetParam();
- }
- std::unique_ptr<const char*[]> argv(new const char*[args.size()]);
- for (int i = 0; i < args.size(); i++) {
- argv[i] = args[i].c_str();
- }
- CommandLineInterface cli;
- CaptureTestStdout();
- CaptureTestStderr();
- int result = cli.Run(args.size(), argv.get());
- captured_stdout_ = GetCapturedTestStdout();
- captured_stderr_ = GetCapturedTestStderr();
- return result == 0;
- }
- void ExpectStdoutMatchesBinaryFile(const std::string& filename) {
- std::string expected_output;
- GOOGLE_CHECK_OK(File::GetContents(filename, &expected_output, true));
- // Don't use EXPECT_EQ because we don't want to print raw binary data to
- // stdout on failure.
- EXPECT_TRUE(captured_stdout_ == expected_output);
- }
- void ExpectStdoutMatchesTextFile(const std::string& filename) {
- std::string expected_output;
- GOOGLE_CHECK_OK(File::GetContents(filename, &expected_output, true));
- ExpectStdoutMatchesText(expected_output);
- }
- void ExpectStdoutMatchesText(const std::string& expected_text) {
- EXPECT_EQ(StripCR(expected_text), StripCR(captured_stdout_));
- }
- void ExpectStderrMatchesText(const std::string& expected_text) {
- EXPECT_EQ(StripCR(expected_text), StripCR(captured_stderr_));
- }
- private:
- void WriteUnittestProtoDescriptorSet() {
- unittest_proto_descriptor_set_filename_ =
- TestTempDir() + "/unittest_proto_descriptor_set.bin";
- FileDescriptorSet file_descriptor_set;
- protobuf_unittest::TestAllTypes test_all_types;
- test_all_types.descriptor()->file()->CopyTo(file_descriptor_set.add_file());
- protobuf_unittest_import::ImportMessage import_message;
- import_message.descriptor()->file()->CopyTo(file_descriptor_set.add_file());
- protobuf_unittest_import::PublicImportMessage public_import_message;
- public_import_message.descriptor()->file()->CopyTo(
- file_descriptor_set.add_file());
- GOOGLE_DCHECK(file_descriptor_set.IsInitialized());
- std::string binary_proto;
- GOOGLE_CHECK(file_descriptor_set.SerializeToString(&binary_proto));
- GOOGLE_CHECK_OK(File::SetContents(unittest_proto_descriptor_set_filename_,
- binary_proto, true));
- }
- int duped_stdin_;
- std::string captured_stdout_;
- std::string captured_stderr_;
- std::string unittest_proto_descriptor_set_filename_;
- };
- TEST_P(EncodeDecodeTest, Encode) {
- RedirectStdinFromFile(TestUtil::GetTestDataPath(
- "net/proto2/internal/"
- "testdata/text_format_unittest_data_oneof_implemented.txt"));
- EXPECT_TRUE(
- Run(TestUtil::MaybeTranslatePath("net/proto2/internal/unittest.proto") +
- " --encode=protobuf_unittest.TestAllTypes"));
- ExpectStdoutMatchesBinaryFile(TestUtil::GetTestDataPath(
- "net/proto2/internal/testdata/golden_message_oneof_implemented"));
- ExpectStderrMatchesText("");
- }
- TEST_P(EncodeDecodeTest, Decode) {
- RedirectStdinFromFile(TestUtil::GetTestDataPath(
- "net/proto2/internal/testdata/golden_message_oneof_implemented"));
- EXPECT_TRUE(
- Run(TestUtil::MaybeTranslatePath("net/proto2/internal/unittest.proto") +
- " --decode=protobuf_unittest.TestAllTypes"));
- ExpectStdoutMatchesTextFile(TestUtil::GetTestDataPath(
- "net/proto2/internal/"
- "testdata/text_format_unittest_data_oneof_implemented.txt"));
- ExpectStderrMatchesText("");
- }
- TEST_P(EncodeDecodeTest, Partial) {
- RedirectStdinFromText("");
- EXPECT_TRUE(
- Run(TestUtil::MaybeTranslatePath("net/proto2/internal/unittest.proto") +
- " --encode=protobuf_unittest.TestRequired"));
- ExpectStdoutMatchesText("");
- ExpectStderrMatchesText(
- "warning: Input message is missing required fields: a, b, c\n");
- }
- TEST_P(EncodeDecodeTest, DecodeRaw) {
- protobuf_unittest::TestAllTypes message;
- message.set_optional_int32(123);
- message.set_optional_string("foo");
- std::string data;
- message.SerializeToString(&data);
- RedirectStdinFromText(data);
- EXPECT_TRUE(Run("--decode_raw"));
- ExpectStdoutMatchesText(
- "1: 123\n"
- "14: \"foo\"\n");
- ExpectStderrMatchesText("");
- }
- TEST_P(EncodeDecodeTest, UnknownType) {
- EXPECT_FALSE(
- Run(TestUtil::MaybeTranslatePath("net/proto2/internal/unittest.proto") +
- " --encode=NoSuchType"));
- ExpectStdoutMatchesText("");
- ExpectStderrMatchesText("Type not defined: NoSuchType\n");
- }
- TEST_P(EncodeDecodeTest, ProtoParseError) {
- EXPECT_FALSE(
- Run("net/proto2/internal/no_such_file.proto "
- "--encode=NoSuchType"));
- ExpectStdoutMatchesText("");
- ExpectStderrMatchesText(
- "net/proto2/internal/no_such_file.proto: No such file or directory\n");
- }
- INSTANTIATE_TEST_SUITE_P(FileDescriptorSetSource, EncodeDecodeTest,
- testing::Values(PROTO_PATH, DESCRIPTOR_SET_IN));
- } // anonymous namespace
- #endif // !GOOGLE_PROTOBUF_HEAP_CHECK_DRACONIAN
- } // namespace compiler
- } // namespace protobuf
- } // namespace google
|