Add a path parsing policy handler for the RoamingProfileLocation policy.

This policy should like most other FilePath policies parse variables
in its content before storing its value in its backing pref.

BUG=726007
TEST=unit_tests

Review-Url: https://codereview.chromium.org/2912353003
Cr-Commit-Position: refs/heads/master@{#476272}
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index 44bd37a..f5c2bb7 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -3520,6 +3520,8 @@
       "obsolete_system/obsolete_system_win.cc",
       "pdf/pdf_extension_util.cc",
       "pdf/pdf_extension_util.h",
+      "policy/local_sync_policy_handler.cc",
+      "policy/local_sync_policy_handler.h",
       "process_singleton_modal_dialog_lock.cc",
       "process_singleton_modal_dialog_lock.h",
       "process_singleton_posix.cc",
diff --git a/chrome/browser/policy/configuration_policy_handler_list_factory.cc b/chrome/browser/policy/configuration_policy_handler_list_factory.cc
index 4981e0b..9bebc11 100644
--- a/chrome/browser/policy/configuration_policy_handler_list_factory.cc
+++ b/chrome/browser/policy/configuration_policy_handler_list_factory.cc
@@ -78,6 +78,7 @@
 
 #if !defined(OS_ANDROID)
 #include "chrome/browser/download/download_dir_policy_handler.h"
+#include "chrome/browser/policy/local_sync_policy_handler.h"
 #endif
 
 #if BUILDFLAG(ENABLE_EXTENSIONS)
@@ -669,9 +670,6 @@
   { key::kRoamingProfileSupportEnabled,
     syncer::prefs::kEnableLocalSyncBackend,
     base::Value::Type::BOOLEAN },
-  { key::kRoamingProfileLocation,
-    syncer::prefs::kLocalSyncBackendDir,
-    base::Value::Type::STRING },
 
   { key::kNetworkTimeQueriesEnabled,
     network_time::prefs::kNetworkTimeQueriesEnabled,
@@ -922,6 +920,7 @@
 
 #if !defined(OS_ANDROID)
   handlers->AddHandler(base::WrapUnique(new DownloadDirPolicyHandler));
+  handlers->AddHandler(base::MakeUnique<LocalSyncPolicyHandler>());
 
   handlers->AddHandler(base::MakeUnique<SimpleSchemaValidatingPolicyHandler>(
       key::kRegisteredProtocolHandlers,
diff --git a/chrome/browser/policy/local_sync_policy_handler.cc b/chrome/browser/policy/local_sync_policy_handler.cc
new file mode 100644
index 0000000..88758efee
--- /dev/null
+++ b/chrome/browser/policy/local_sync_policy_handler.cc
@@ -0,0 +1,36 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/policy/local_sync_policy_handler.h"
+
+#include "base/files/file_path.h"
+#include "base/memory/ptr_util.h"
+#include "base/values.h"
+#include "chrome/browser/policy/policy_path_parser.h"
+#include "components/policy/core/common/policy_map.h"
+#include "components/policy/policy_constants.h"
+#include "components/prefs/pref_value_map.h"
+#include "components/sync/base/pref_names.h"
+
+namespace policy {
+
+LocalSyncPolicyHandler::LocalSyncPolicyHandler()
+    : TypeCheckingPolicyHandler(key::kRoamingProfileLocation,
+                                base::Value::Type::STRING) {}
+
+LocalSyncPolicyHandler::~LocalSyncPolicyHandler() {}
+
+void LocalSyncPolicyHandler::ApplyPolicySettings(const PolicyMap& policies,
+                                                 PrefValueMap* prefs) {
+  const base::Value* value = policies.GetValue(policy_name());
+  base::FilePath::StringType string_value;
+  if (value && value->GetAsString(&string_value)) {
+    base::FilePath::StringType expanded_value =
+        policy::path_parser::ExpandPathVariables(string_value);
+    prefs->SetValue(syncer::prefs::kLocalSyncBackendDir,
+                    base::MakeUnique<base::Value>(expanded_value));
+  }
+}
+
+}  // namespace policy
diff --git a/chrome/browser/policy/local_sync_policy_handler.h b/chrome/browser/policy/local_sync_policy_handler.h
new file mode 100644
index 0000000..99e9802
--- /dev/null
+++ b/chrome/browser/policy/local_sync_policy_handler.h
@@ -0,0 +1,30 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_POLICY_LOCAL_SYNC_POLICY_HANDLER_H_
+#define CHROME_BROWSER_POLICY_LOCAL_SYNC_POLICY_HANDLER_H_
+
+#include "base/compiler_specific.h"
+#include "base/macros.h"
+#include "components/policy/core/browser/configuration_policy_handler.h"
+
+namespace policy {
+
+// ConfigurationPolicyHandler for the RoamingProfileLocation policy.
+class LocalSyncPolicyHandler : public TypeCheckingPolicyHandler {
+ public:
+  LocalSyncPolicyHandler();
+  ~LocalSyncPolicyHandler() override;
+
+  // ConfigurationPolicyHandler methods:
+  void ApplyPolicySettings(const PolicyMap& policies,
+                           PrefValueMap* prefs) override;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(LocalSyncPolicyHandler);
+};
+
+}  // namespace policy
+
+#endif  // CHROME_BROWSER_POLICY_LOCAL_SYNC_POLICY_HANDLER_H_
diff --git a/chrome/browser/policy/local_sync_policy_handler_unittest.cc b/chrome/browser/policy/local_sync_policy_handler_unittest.cc
new file mode 100644
index 0000000..075c586
--- /dev/null
+++ b/chrome/browser/policy/local_sync_policy_handler_unittest.cc
@@ -0,0 +1,56 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <string>
+
+#include "base/memory/ptr_util.h"
+#include "base/values.h"
+#include "chrome/browser/policy/local_sync_policy_handler.h"
+#include "components/policy/core/common/policy_map.h"
+#include "components/policy/core/common/policy_types.h"
+#include "components/policy/policy_constants.h"
+#include "components/prefs/pref_value_map.h"
+#include "components/sync/base/pref_names.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace policy {
+
+class LocalSyncPolicyTest : public testing::Test {
+ protected:
+  PolicyMap policy_;
+  LocalSyncPolicyHandler handler_;
+  PrefValueMap prefs_;
+};
+
+TEST_F(LocalSyncPolicyTest, Default) {
+  handler_.ApplyPolicySettings(policy_, &prefs_);
+  EXPECT_FALSE(prefs_.GetValue(syncer::prefs::kLocalSyncBackendDir, nullptr));
+}
+
+// RoamingProfileLocation policy expects a string; give it a boolean.
+TEST_F(LocalSyncPolicyTest, SetPolicyInvalid) {
+  policy_.Set(key::kRoamingProfileLocation, POLICY_LEVEL_MANDATORY,
+              POLICY_SCOPE_USER, POLICY_SOURCE_CLOUD,
+              base::MakeUnique<base::Value>(false), nullptr);
+  handler_.ApplyPolicySettings(policy_, &prefs_);
+  EXPECT_FALSE(prefs_.GetValue(syncer::prefs::kLocalSyncBackendDir, nullptr));
+}
+
+// Use a variable in the value. It should be expanded by the handler.
+TEST_F(LocalSyncPolicyTest, SetPolicyValid) {
+  const std::string in = "${user_name}/foo";
+  policy_.Set(key::kRoamingProfileLocation, POLICY_LEVEL_MANDATORY,
+              POLICY_SCOPE_USER, POLICY_SOURCE_CLOUD,
+              base::MakeUnique<base::Value>(in), nullptr);
+  handler_.ApplyPolicySettings(policy_, &prefs_);
+
+  const base::Value* value;
+  ASSERT_TRUE(prefs_.GetValue(syncer::prefs::kLocalSyncBackendDir, &value));
+  std::string out;
+  ASSERT_TRUE(value->GetAsString(&out));
+  EXPECT_NE(std::string::npos, out.find("foo"));
+  EXPECT_EQ(std::string::npos, out.find("${user_name}"));
+}
+
+}  // namespace policy
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index 8fa665c0..39fd326 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -3724,6 +3724,7 @@
       "../browser/media/router/mojo/media_route_controller_unittest.cc",
       "../browser/media/router/mojo/media_router_mojo_impl_unittest.cc",
       "../browser/media/router/mojo/media_router_mojo_metrics_unittest.cc",
+      "../browser/policy/local_sync_policy_handler_unittest.cc",
       "../browser/renderer_context_menu/render_view_context_menu_test_util.cc",
       "../browser/renderer_context_menu/render_view_context_menu_test_util.h",
       "../browser/ui/autofill/save_card_bubble_controller_impl_unittest.cc",