| // Copyright 2017 The Bazel Authors. All rights reserved. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| #include "src/main/cpp/option_processor.h" |
| |
| #include <memory> |
| |
| #include "src/main/cpp/bazel_startup_options.h" |
| #include "src/main/cpp/blaze_util.h" |
| #include "src/main/cpp/blaze_util_platform.h" |
| #include "src/main/cpp/option_processor-internal.h" |
| #include "src/main/cpp/util/file.h" |
| #include "src/main/cpp/util/file_platform.h" |
| #include "src/main/cpp/util/path.h" |
| #include "src/main/cpp/workspace_layout.h" |
| #include "googletest/include/gtest/gtest.h" |
| |
| namespace blaze { |
| |
| class OptionProcessorTest : public ::testing::Test { |
| protected: |
| OptionProcessorTest() |
| : workspace_( |
| blaze_util::JoinPath(blaze::GetPathEnv("TEST_TMPDIR"), "testdir")), |
| cwd_("cwd"), |
| workspace_layout_(new WorkspaceLayout()) {} |
| |
| ~OptionProcessorTest() override {} |
| |
| void SetUp() override { |
| ASSERT_TRUE(blaze_util::MakeDirectories(workspace_, 0755)); |
| option_processor_.reset(new OptionProcessor( |
| workspace_layout_.get(), |
| std::unique_ptr<StartupOptions>( |
| new BazelStartupOptions(workspace_layout_.get())))); |
| } |
| |
| void TearDown() override { |
| // TODO(bazel-team): The code below deletes all the files in the workspace |
| // but it intentionally skips directories. As a consequence, there may be |
| // empty directories from test to test. Remove this once |
| // blaze_util::DeleteDirectories(path) exists. |
| std::vector<std::string> files_in_workspace; |
| blaze_util::GetAllFilesUnder(workspace_, &files_in_workspace); |
| for (const std::string& file : files_in_workspace) { |
| blaze_util::UnlinkPath(file); |
| } |
| } |
| |
| void FailedSplitCommandLineTest(const std::vector<std::string>& args, |
| const std::string& expected_error) const { |
| std::string error; |
| const std::unique_ptr<CommandLine> result = |
| option_processor_->SplitCommandLine(args, &error); |
| ASSERT_EQ(expected_error, error); |
| ASSERT_EQ(nullptr, result); |
| } |
| |
| void SuccessfulSplitCommandLineTest(const std::vector<std::string>& args, |
| const CommandLine& expected) const { |
| std::string error; |
| const std::unique_ptr<CommandLine> result = |
| option_processor_->SplitCommandLine(args, &error); |
| |
| ASSERT_EQ("", error); |
| EXPECT_EQ(expected.path_to_binary, result->path_to_binary); |
| EXPECT_EQ(expected.startup_args, result->startup_args); |
| EXPECT_EQ(expected.command, result->command); |
| EXPECT_EQ(expected.command_args, result->command_args); |
| } |
| |
| void HelpArgIsInterpretedAsACommand(const std::string& arg) { |
| const std::vector<std::string> args = {"bazel", arg}; |
| std::string error; |
| ASSERT_EQ(blaze_exit_code::SUCCESS, |
| option_processor_->ParseOptions(args, workspace_, cwd_, &error)) |
| << error; |
| ASSERT_EQ("", error); |
| |
| EXPECT_EQ(arg, option_processor_->GetCommand()); |
| EXPECT_EQ(std::vector<std::string>({}), |
| option_processor_->GetExplicitCommandArguments()); |
| } |
| |
| const std::string workspace_; |
| const std::string cwd_; |
| const std::unique_ptr<WorkspaceLayout> workspace_layout_; |
| std::unique_ptr<OptionProcessor> option_processor_; |
| }; |
| |
| TEST_F(OptionProcessorTest, CanParseOptions) { |
| const std::vector<std::string> args = {"bazel", "--host_jvm_args=MyParam", |
| "--nobatch", "command", |
| "--flag", "//my:target", |
| "--flag2=42"}; |
| std::string error; |
| ASSERT_EQ(blaze_exit_code::SUCCESS, |
| option_processor_->ParseOptions(args, workspace_, cwd_, &error)) |
| << error; |
| |
| ASSERT_EQ("", error); |
| #if defined(_WIN32) || defined(__CYGWIN__) |
| ASSERT_EQ(size_t(2), |
| option_processor_->GetParsedStartupOptions()->host_jvm_args.size()); |
| const std::string win_unix_root("-Dbazel.windows_unix_root="); |
| const std::string host_jvm_args_0 = |
| option_processor_->GetParsedStartupOptions()->host_jvm_args[0]; |
| EXPECT_EQ(host_jvm_args_0.find(win_unix_root), 0) << host_jvm_args_0; |
| EXPECT_GT(host_jvm_args_0.size(), win_unix_root.size()); |
| EXPECT_EQ("MyParam", |
| option_processor_->GetParsedStartupOptions()->host_jvm_args[1]); |
| #else // ! (defined(_WIN32) || defined(__CYGWIN__)) |
| ASSERT_EQ(size_t(1), |
| option_processor_->GetParsedStartupOptions()->host_jvm_args.size()); |
| EXPECT_EQ("MyParam", |
| option_processor_->GetParsedStartupOptions()->host_jvm_args[0]); |
| #endif // defined(_WIN32) || defined(__CYGWIN__) |
| EXPECT_FALSE(option_processor_->GetParsedStartupOptions()->batch); |
| |
| EXPECT_EQ("command", option_processor_->GetCommand()); |
| |
| EXPECT_EQ(std::vector<std::string>({"--flag", "//my:target", "--flag2=42"}), |
| option_processor_->GetExplicitCommandArguments()); |
| } |
| |
| TEST_F(OptionProcessorTest, CanParseHelpCommandSurroundedByOtherArgs) { |
| const std::vector<std::string> args = {"bazel", "--host_jvm_args=MyParam", |
| "--nobatch", "help", |
| "--flag", "//my:target", |
| "--flag2=42"}; |
| std::string error; |
| ASSERT_EQ(blaze_exit_code::SUCCESS, |
| option_processor_->ParseOptions(args, workspace_, cwd_, &error)) |
| << error; |
| |
| ASSERT_EQ("", error); |
| #if defined(_WIN32) || defined(__CYGWIN__) |
| ASSERT_EQ(size_t(2), |
| option_processor_->GetParsedStartupOptions()->host_jvm_args.size()); |
| const std::string win_unix_root("-Dbazel.windows_unix_root="); |
| const std::string host_jvm_args_0 = |
| option_processor_->GetParsedStartupOptions()->host_jvm_args[0]; |
| EXPECT_EQ(host_jvm_args_0.find(win_unix_root), 0) << host_jvm_args_0; |
| EXPECT_GT(host_jvm_args_0.size(), win_unix_root.size()); |
| EXPECT_EQ("MyParam", |
| option_processor_->GetParsedStartupOptions()->host_jvm_args[1]); |
| #else // ! (defined(_WIN32) || defined(__CYGWIN__)) |
| ASSERT_EQ(size_t(1), |
| option_processor_->GetParsedStartupOptions()->host_jvm_args.size()); |
| EXPECT_EQ("MyParam", |
| option_processor_->GetParsedStartupOptions()->host_jvm_args[0]); |
| #endif // defined(_WIN32) || defined(__CYGWIN__) |
| EXPECT_FALSE(option_processor_->GetParsedStartupOptions()->batch); |
| |
| EXPECT_EQ("help", option_processor_->GetCommand()); |
| |
| EXPECT_EQ(std::vector<std::string>({"--flag", "//my:target", "--flag2=42"}), |
| option_processor_->GetExplicitCommandArguments()); |
| } |
| |
| TEST_F(OptionProcessorTest, CanParseHelpCommand) { |
| HelpArgIsInterpretedAsACommand("help"); |
| } |
| |
| TEST_F(OptionProcessorTest, CanParseHelpShortFlag) { |
| HelpArgIsInterpretedAsACommand("-h"); |
| } |
| |
| TEST_F(OptionProcessorTest, CanParseHelpFlag) { |
| HelpArgIsInterpretedAsACommand("-help"); |
| } |
| |
| TEST_F(OptionProcessorTest, CanParseEmptyArgs) { |
| const std::vector<std::string> args = {"bazel"}; |
| std::string error; |
| ASSERT_EQ(blaze_exit_code::SUCCESS, |
| option_processor_->ParseOptions(args, workspace_, cwd_, &error)) |
| << error; |
| ASSERT_EQ("", error); |
| |
| EXPECT_EQ("", option_processor_->GetCommand()); |
| |
| EXPECT_EQ(std::vector<std::string>({}), |
| option_processor_->GetExplicitCommandArguments()); |
| } |
| |
| TEST_F(OptionProcessorTest, CanParseDifferentStartupArgs) { |
| const std::vector<std::string> args = |
| {"bazel", |
| "--nobatch", "--host_jvm_args=MyParam", "--host_jvm_args", "42"}; |
| std::string error; |
| ASSERT_EQ(blaze_exit_code::SUCCESS, |
| option_processor_->ParseOptions(args, workspace_, cwd_, &error)) |
| << error; |
| ASSERT_EQ("", error); |
| |
| #if defined(_WIN32) || defined(__CYGWIN__) |
| ASSERT_EQ(size_t(3), |
| option_processor_->GetParsedStartupOptions()->host_jvm_args.size()); |
| const std::string win_unix_root("-Dbazel.windows_unix_root="); |
| const std::string host_jvm_args_0 = |
| option_processor_->GetParsedStartupOptions()->host_jvm_args[0]; |
| EXPECT_EQ(host_jvm_args_0.find(win_unix_root), 0) << host_jvm_args_0; |
| EXPECT_GT(host_jvm_args_0.size(), win_unix_root.size()); |
| EXPECT_EQ("MyParam", |
| option_processor_->GetParsedStartupOptions()->host_jvm_args[1]); |
| EXPECT_EQ("42", |
| option_processor_->GetParsedStartupOptions()->host_jvm_args[2]); |
| #else // ! (defined(_WIN32) || defined(__CYGWIN__)) |
| ASSERT_EQ(size_t(2), |
| option_processor_->GetParsedStartupOptions()->host_jvm_args.size()); |
| EXPECT_EQ("MyParam", |
| option_processor_->GetParsedStartupOptions()->host_jvm_args[0]); |
| EXPECT_EQ("42", |
| option_processor_->GetParsedStartupOptions()->host_jvm_args[1]); |
| #endif // defined(_WIN32) || defined(__CYGWIN__) |
| |
| EXPECT_EQ("", option_processor_->GetCommand()); |
| |
| EXPECT_EQ(std::vector<std::string>({}), |
| option_processor_->GetExplicitCommandArguments()); |
| } |
| |
| TEST_F(OptionProcessorTest, SplitCommandLineWithEmptyArgs) { |
| FailedSplitCommandLineTest({}, "Unable to split command line, args is empty"); |
| } |
| |
| TEST_F(OptionProcessorTest, SplitCommandLineWithAllParams) { |
| SuccessfulSplitCommandLineTest( |
| {"bazel", "--ignore_all_rc_files", "build", "--bar", ":mytarget"}, |
| CommandLine("bazel", {"--ignore_all_rc_files"}, "build", |
| {"--bar", ":mytarget"})); |
| } |
| |
| TEST_F(OptionProcessorTest, SplitCommandLineWithAbsolutePathToBinary) { |
| SuccessfulSplitCommandLineTest( |
| {"mybazel", "build", ":mytarget"}, |
| CommandLine("mybazel", {}, "build", {":mytarget"})); |
| } |
| |
| TEST_F(OptionProcessorTest, SplitCommandLineWithUnaryStartupWithEquals) { |
| SuccessfulSplitCommandLineTest( |
| {"bazel", "--bazelrc=foo", "build", ":mytarget"}, |
| CommandLine("bazel", {"--bazelrc=foo"}, "build", {":mytarget"})); |
| } |
| |
| TEST_F(OptionProcessorTest, |
| SplitCommandLineWithUnaryStartupWithoutEquals) { |
| SuccessfulSplitCommandLineTest( |
| {"bazel", "--bazelrc", "foo", "build", ":mytarget"}, |
| CommandLine("bazel", {"--bazelrc=foo"}, "build", {":mytarget"})); |
| } |
| |
| TEST_F(OptionProcessorTest, SplitCommandLineWithIncompleteUnaryOption) { |
| FailedSplitCommandLineTest( |
| {"bazel", "--bazelrc"}, |
| "Startup option '--bazelrc' expects a value.\n" |
| "Usage: '--bazelrc=somevalue' or '--bazelrc somevalue'.\n" |
| " For more info, run 'bazel help startup_options'."); |
| } |
| |
| TEST_F(OptionProcessorTest, SplitCommandLineWithMultipleStartup) { |
| SuccessfulSplitCommandLineTest( |
| {"bazel", "--bazelrc", "foo", "--ignore_all_rc_files", "build", |
| ":mytarget"}, |
| CommandLine("bazel", {"--bazelrc=foo", "--ignore_all_rc_files"}, "build", |
| {":mytarget"})); |
| } |
| |
| TEST_F(OptionProcessorTest, SplitCommandLineWithNoStartupArgs) { |
| SuccessfulSplitCommandLineTest( |
| {"bazel", "build", ":mytarget"}, |
| CommandLine("bazel", {}, "build", {":mytarget"})); |
| } |
| |
| TEST_F(OptionProcessorTest, SplitCommandLineWithNoCommandArgs) { |
| SuccessfulSplitCommandLineTest({"bazel", "build"}, |
| CommandLine("bazel", {}, "build", {})); |
| } |
| |
| TEST_F(OptionProcessorTest, SplitCommandLineWithBlazeHelp) { |
| SuccessfulSplitCommandLineTest({"bazel", "help"}, |
| CommandLine("bazel", {}, "help", {})); |
| |
| SuccessfulSplitCommandLineTest({"bazel", "-h"}, |
| CommandLine("bazel", {}, "-h", {})); |
| |
| SuccessfulSplitCommandLineTest({"bazel", "-help"}, |
| CommandLine("bazel", {}, "-help", {})); |
| |
| SuccessfulSplitCommandLineTest({"bazel", "--help"}, |
| CommandLine("bazel", {}, "--help", {})); |
| } |
| |
| TEST_F(OptionProcessorTest, SplitCommandLineWithBlazeVersion) { |
| SuccessfulSplitCommandLineTest({"bazel", "version"}, |
| CommandLine("bazel", {}, "version", {})); |
| } |
| |
| TEST_F(OptionProcessorTest, SplitCommandLineWithMultipleCommandArgs) { |
| SuccessfulSplitCommandLineTest( |
| {"bazel", "build", "--foo", "-s", ":mytarget"}, |
| CommandLine("bazel", {}, "build", {"--foo", "-s", ":mytarget"})); |
| } |
| |
| TEST_F(OptionProcessorTest, |
| SplitCommandLineFailsWithDashDashInStartupArgs) { |
| FailedSplitCommandLineTest( |
| {"bazel", "--"}, |
| "Unknown startup option: '--'.\n" |
| " For more info, run 'bazel help startup_options'."); |
| } |
| |
| TEST_F(OptionProcessorTest, SplitCommandLineWithDashDash) { |
| SuccessfulSplitCommandLineTest( |
| {"bazel", "--ignore_all_rc_files", "build", "--b", "--", ":mytarget"}, |
| CommandLine("bazel", {"--ignore_all_rc_files"}, "build", |
| {"--b", "--", ":mytarget"})); |
| } |
| |
| TEST_F(OptionProcessorTest, TestDedupePathsOmitsInvalidPath) { |
| std::vector<std::string> input = {"foo"}; |
| std::vector<std::string> expected = {}; |
| ASSERT_EQ(expected, internal::DedupeBlazercPaths(input)); |
| } |
| |
| TEST_F(OptionProcessorTest, TestDedupePathsOmitsEmptyPath) { |
| std::vector<std::string> input = {""}; |
| std::vector<std::string> expected = {}; |
| ASSERT_EQ(expected, internal::DedupeBlazercPaths(input)); |
| } |
| |
| TEST_F(OptionProcessorTest, TestDedupePathsWithDifferentFiles) { |
| std::string foo_path = blaze_util::JoinPath(workspace_, "foo"); |
| std::string bar_path = blaze_util::JoinPath(workspace_, "bar"); |
| |
| ASSERT_TRUE(blaze_util::WriteFile("foo", foo_path)); |
| ASSERT_TRUE(blaze_util::WriteFile("bar", bar_path)); |
| |
| std::vector<std::string> input = {foo_path, bar_path}; |
| ASSERT_EQ(input, internal::DedupeBlazercPaths(input)); |
| } |
| |
| TEST_F(OptionProcessorTest, TestDedupePathsWithSameFile) { |
| std::string foo_path = blaze_util::JoinPath(workspace_, "foo"); |
| |
| ASSERT_TRUE(blaze_util::WriteFile("foo", foo_path)); |
| |
| std::vector<std::string> input = {foo_path, foo_path}; |
| std::vector<std::string> expected = {foo_path}; |
| ASSERT_EQ(expected, internal::DedupeBlazercPaths(input)); |
| } |
| |
| TEST_F(OptionProcessorTest, TestDedupePathsWithRelativePath) { |
| std::string dir(blaze_util::JoinPath(workspace_, "dir")); |
| std::string foo_path(blaze_util::JoinPath(dir, "foo")); |
| std::string relative_foo_path(blaze_util::JoinPath(dir, "../dir/foo")); |
| |
| ASSERT_TRUE(blaze_util::MakeDirectories(dir, 0755)); |
| ASSERT_TRUE(blaze_util::WriteFile("foo", foo_path)); |
| |
| std::vector<std::string> input = {foo_path, relative_foo_path}; |
| std::vector<std::string> expected = {foo_path}; |
| ASSERT_EQ(expected, internal::DedupeBlazercPaths(input)); |
| } |
| |
| #if !defined(_WIN32) && !defined(__CYGWIN__) |
| static bool Symlink(const std::string& old_path, const std::string& new_path) { |
| return symlink(old_path.c_str(), new_path.c_str()) == 0; |
| } |
| |
| TEST_F(OptionProcessorTest, TestDedupePathsWithSymbolicLink) { |
| std::string foo_path = blaze_util::JoinPath(workspace_, "foo"); |
| std::string sym_foo_path = blaze_util::JoinPath(workspace_, "sym_foo"); |
| |
| ASSERT_TRUE(blaze_util::WriteFile("foo", foo_path)); |
| ASSERT_TRUE(Symlink(foo_path, sym_foo_path)); |
| std::vector<std::string> input = {foo_path, sym_foo_path}; |
| std::vector<std::string> expected = {foo_path}; |
| ASSERT_EQ(expected, internal::DedupeBlazercPaths(input)); |
| } |
| |
| |
| TEST_F(OptionProcessorTest, |
| SplitCommandLineFailsWithDeprecatedOptionInStartupArgs) { |
| FailedSplitCommandLineTest( |
| {"bazel", "--nomaster_bazelrc"}, |
| "Unknown startup option: '--nomaster_bazelrc'.\n" |
| " For more info, run 'bazel help startup_options'."); |
| } |
| #endif // !defined(_WIN32) && !defined(__CYGWIN__) |
| |
| } // namespace blaze |