| // Copyright 2016 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/startup_options.h" | 
 |  | 
 | #include <stdlib.h> | 
 |  | 
 | #include <memory> | 
 |  | 
 | #include "src/main/cpp/blaze_util_platform.h" | 
 | #ifdef __linux | 
 | #include "src/main/cpp/util/file_platform.h" | 
 | #endif  // __linux | 
 | #include "src/main/cpp/workspace_layout.h" | 
 | #include "src/test/cpp/test_util.h" | 
 | #include "googletest/include/gtest/gtest.h" | 
 |  | 
 | namespace blaze { | 
 |  | 
 | // Minimal StartupOptions class for testing. | 
 | class FakeStartupOptions : public StartupOptions { | 
 |  public: | 
 |   FakeStartupOptions(const WorkspaceLayout *workspace_layout) | 
 |       : StartupOptions("Bazel", workspace_layout) {} | 
 |   blaze_exit_code::ExitCode ProcessArgExtra( | 
 |       const char *arg, const char *next_arg, const std::string &rcfile, | 
 |       const char **value, bool *is_processed, std::string *error) override { | 
 |     *is_processed = false; | 
 |     return blaze_exit_code::SUCCESS; | 
 |   } | 
 |   void MaybeLogStartupOptionWarnings() const override {} | 
 |  | 
 |  protected: | 
 |   std::string GetRcFileBaseName() const override { return ".bazelrc"; } | 
 | }; | 
 |  | 
 | class StartupOptionsTest : public ::testing::Test { | 
 |  protected: | 
 |   StartupOptionsTest() : workspace_layout_(new WorkspaceLayout()) {} | 
 |   ~StartupOptionsTest() = default; | 
 |  | 
 |   void SetUp() override { | 
 |     // This knowingly ignores the possibility of these environment variables | 
 |     // being unset because we expect our test runner to set them in all cases. | 
 |     // Otherwise, we'll crash here, but this keeps our code simpler. | 
 |     old_home_ = GetHomeDir(); | 
 |     old_test_tmpdir_ = GetPathEnv("TEST_TMPDIR"); | 
 |  | 
 |     ReinitStartupOptions(); | 
 |   } | 
 |  | 
 |   void TearDown() override { | 
 |     SetEnv("HOME", old_home_); | 
 |     SetEnv("TEST_TMPDIR", old_test_tmpdir_); | 
 |   } | 
 |  | 
 |   // Recreates startup_options_ after changes to the environment. | 
 |   void ReinitStartupOptions() { | 
 |     startup_options_.reset(new FakeStartupOptions(workspace_layout_.get())); | 
 |   } | 
 |  | 
 |  private: | 
 |   std::unique_ptr<WorkspaceLayout> workspace_layout_; | 
 |  | 
 |  protected: | 
 |   std::unique_ptr<StartupOptions> startup_options_; | 
 |  | 
 |  private: | 
 |   std::string old_home_; | 
 |   std::string old_test_tmpdir_; | 
 | }; | 
 |  | 
 | TEST_F(StartupOptionsTest, ProductName) { | 
 |   ASSERT_EQ("Bazel", startup_options_->product_name); | 
 | } | 
 |  | 
 | TEST_F(StartupOptionsTest, JavaLoggingOptions) { | 
 |   ASSERT_EQ("com.google.devtools.build.lib.util.SingleLineFormatter", | 
 |             startup_options_->java_logging_formatter); | 
 | } | 
 |  | 
 | // TODO(bazel-team): remove the ifdef guard once the implementation of | 
 | // GetOutputRoot is stable among the different platforms. | 
 | #ifdef __linux | 
 | TEST_F(StartupOptionsTest, OutputRootPreferTestTmpdirIfSet) { | 
 |   SetEnv("HOME", "/nonexistent/home"); | 
 |   SetEnv("XDG_CACHE_HOME", "/nonexistent/cache"); | 
 |   SetEnv("TEST_TMPDIR", "/nonexistent/tmpdir"); | 
 |   ReinitStartupOptions(); | 
 |  | 
 |   ASSERT_EQ("/nonexistent/tmpdir", startup_options_->output_root); | 
 | } | 
 |  | 
 | TEST_F(StartupOptionsTest, | 
 |        OutputRootPreferXdgCacheHomeIfSetAndTestTmpdirUnset) { | 
 |   SetEnv("HOME", "/nonexistent/home"); | 
 |   SetEnv("XDG_CACHE_HOME", "/nonexistent/cache"); | 
 |   UnsetEnv("TEST_TMPDIR"); | 
 |   ReinitStartupOptions(); | 
 |  | 
 |   ASSERT_EQ("/nonexistent/cache/bazel", startup_options_->output_root); | 
 | } | 
 |  | 
 | TEST_F(StartupOptionsTest, OutputRootUseHomeDirectory) { | 
 |   SetEnv("HOME", "/nonexistent/home"); | 
 |   UnsetEnv("TEST_TMPDIR"); | 
 |   UnsetEnv("XDG_CACHE_HOME"); | 
 |   ReinitStartupOptions(); | 
 |  | 
 |   ASSERT_EQ("/nonexistent/home/.cache/bazel", startup_options_->output_root); | 
 | } | 
 |  | 
 | TEST_F(StartupOptionsTest, OutputRootIsAbsoluteAndNotShellExpanded) { | 
 |   SetEnv("TEST_TMPDIR", "~/\"$foo/test\""); | 
 |   SetEnv("XDG_CACHE_HOME", "~/cache${bar}"); | 
 |   SetEnv("HOME", "~/home$(echo baz)"); | 
 |  | 
 |   ReinitStartupOptions(); | 
 |   ASSERT_EQ(blaze_util::GetCwd() + "/~/\"$foo/test\"", | 
 |             startup_options_->output_root); | 
 |  | 
 |   UnsetEnv("TEST_TMPDIR"); | 
 |   ReinitStartupOptions(); | 
 |   ASSERT_EQ(blaze_util::GetCwd() + "/~/cache${bar}/bazel", | 
 |             startup_options_->output_root); | 
 |  | 
 |   UnsetEnv("XDG_CACHE_HOME"); | 
 |   ReinitStartupOptions(); | 
 |   ASSERT_EQ(blaze_util::GetCwd() + "/~/home$(echo baz)/.cache/bazel", | 
 |             startup_options_->output_root); | 
 | } | 
 | #endif  // __linux | 
 |  | 
 | TEST_F(StartupOptionsTest, OutputUserRootTildeExpansion) { | 
 | #if defined(_WIN32) | 
 |   std::string home = "C:/nonexistent/home/"; | 
 | #else | 
 |   std::string home = "/nonexistent/home/"; | 
 | #endif | 
 |  | 
 |   SetEnv("HOME", home); | 
 |  | 
 |   std::string error; | 
 |  | 
 |   { | 
 |     const std::vector<RcStartupFlag> flags{ | 
 |         RcStartupFlag("somewhere", "--output_user_root=~/test"), | 
 |     }; | 
 |  | 
 |     const blaze_exit_code::ExitCode ec = | 
 |         startup_options_->ProcessArgs(flags, &error); | 
 |  | 
 |     ASSERT_EQ(blaze_exit_code::SUCCESS, ec) | 
 |         << "ProcessArgs failed with error " << error; | 
 |  | 
 |     EXPECT_EQ(blaze_util::JoinPath(home, "test"), | 
 |               startup_options_->output_user_root); | 
 |   } | 
 |  | 
 |   { | 
 |     const std::vector<RcStartupFlag> flags{ | 
 |         RcStartupFlag("somewhere", "--output_user_root=~"), | 
 |     }; | 
 |  | 
 |     const blaze_exit_code::ExitCode ec = | 
 |         startup_options_->ProcessArgs(flags, &error); | 
 |  | 
 |     ASSERT_EQ(blaze_exit_code::SUCCESS, ec) | 
 |         << "ProcessArgs failed with error " << error; | 
 |  | 
 |     EXPECT_EQ(home, startup_options_->output_user_root); | 
 |   } | 
 | } | 
 |  | 
 | TEST_F(StartupOptionsTest, EmptyFlagsAreInvalidTest) { | 
 |   { | 
 |     bool result; | 
 |     std::string error; | 
 |     EXPECT_TRUE(startup_options_->MaybeCheckValidNullary("", &result, &error)); | 
 |     EXPECT_FALSE(result); | 
 |   } | 
 |  | 
 |   { | 
 |     bool result; | 
 |     std::string error; | 
 |     EXPECT_TRUE( | 
 |         startup_options_->MaybeCheckValidNullary("--", &result, &error)); | 
 |     EXPECT_FALSE(result); | 
 |   } | 
 |  | 
 |   EXPECT_FALSE(startup_options_->IsUnary("")); | 
 |   EXPECT_FALSE(startup_options_->IsUnary("--")); | 
 | } | 
 |  | 
 | TEST_F(StartupOptionsTest, ProcessSpaceSeparatedArgsTest) { | 
 |   std::string error; | 
 |   const std::vector<RcStartupFlag> flags{ | 
 |       RcStartupFlag("somewhere", "--max_idle_secs"), | 
 |       RcStartupFlag("somewhere", "42")}; | 
 |  | 
 |   const blaze_exit_code::ExitCode ec = | 
 |       startup_options_->ProcessArgs(flags, &error); | 
 |   ASSERT_EQ(blaze_exit_code::SUCCESS, ec) | 
 |       << "ProcessArgs failed with error " << error; | 
 |   EXPECT_EQ(42, startup_options_->max_idle_secs); | 
 |  | 
 |   EXPECT_EQ("somewhere", startup_options_->original_startup_options_[0].source); | 
 |   EXPECT_EQ("--max_idle_secs=42", | 
 |             startup_options_->original_startup_options_[0].value); | 
 | } | 
 |  | 
 | TEST_F(StartupOptionsTest, ProcessEqualsSeparatedArgsTest) { | 
 |   std::string error; | 
 |   const std::vector<RcStartupFlag> flags{ | 
 |       RcStartupFlag("somewhere", "--max_idle_secs=36")}; | 
 |  | 
 |   const blaze_exit_code::ExitCode ec = | 
 |       startup_options_->ProcessArgs(flags, &error); | 
 |   ASSERT_EQ(ec, blaze_exit_code::SUCCESS) | 
 |       << "ProcessArgs failed with error " << error; | 
 |   EXPECT_EQ(36, startup_options_->max_idle_secs); | 
 |  | 
 |   EXPECT_EQ("somewhere", startup_options_->original_startup_options_[0].source); | 
 |   EXPECT_EQ("--max_idle_secs=36", | 
 |             startup_options_->original_startup_options_[0].value); | 
 | } | 
 |  | 
 | TEST_F(StartupOptionsTest, ProcessIncorrectArgValueTest) { | 
 |   std::string error; | 
 |   const std::vector<RcStartupFlag> flags{ | 
 |       RcStartupFlag("somewhere", "--max_idle_secs=notANumber")}; | 
 |  | 
 |   const blaze_exit_code::ExitCode ec = | 
 |       startup_options_->ProcessArgs(flags, &error); | 
 |   ASSERT_EQ(blaze_exit_code::BAD_ARGV, ec) | 
 |       << "ProcessArgs failed with the wrong error " << error; | 
 |  | 
 |   // Even for a failing args processing step, expect the original value | 
 |   // to be stored. | 
 |   EXPECT_EQ("somewhere", startup_options_->original_startup_options_[0].source); | 
 |   EXPECT_EQ("--max_idle_secs=notANumber", | 
 |             startup_options_->original_startup_options_[0].value); | 
 | } | 
 |  | 
 | TEST_F(StartupOptionsTest, ProcessArgsWithMultipleArgstest) { | 
 |   const std::vector<RcStartupFlag> flags{ | 
 |       RcStartupFlag("somewhere", "--max_idle_secs=36"), | 
 |       RcStartupFlag("somewhereElse", "--nowrite_command_log")}; | 
 |  | 
 |   std::string error; | 
 |   const blaze_exit_code::ExitCode ec = | 
 |       startup_options_->ProcessArgs(flags, &error); | 
 |   ASSERT_EQ(ec, blaze_exit_code::SUCCESS) | 
 |       << "ProcessArgs failed with error " << error; | 
 |   EXPECT_EQ(36, startup_options_->max_idle_secs); | 
 |   EXPECT_FALSE(startup_options_->write_command_log); | 
 |  | 
 |   EXPECT_EQ("somewhere", startup_options_->original_startup_options_[0].source); | 
 |   EXPECT_EQ("--max_idle_secs=36", | 
 |             startup_options_->original_startup_options_[0].value); | 
 |  | 
 |   EXPECT_EQ("somewhereElse", | 
 |             startup_options_->original_startup_options_[1].source); | 
 |   EXPECT_EQ("--nowrite_command_log", | 
 |             startup_options_->original_startup_options_[1].value); | 
 | } | 
 |  | 
 | }  // namespace blaze |