inputs: Test DeleteSurroundingText in Lacros.

Add a new test API and capability to test for DeleteSurroundingText.
Important to note that DeleteSurroundingText only works when the
surrounding text tracker has the initial surrounding text value, so
the test needs to wait for that.

Bug: 1434957
Change-Id: I5ed511edf7999fdb5cae09f10b89106702ec8f79
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4498185
Reviewed-by: Hidehiko Abe <hidehiko@chromium.org>
Commit-Queue: Darren Shen <shend@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1138206}
diff --git a/chrome/browser/ash/crosapi/input_method_test_interface_ash.cc b/chrome/browser/ash/crosapi/input_method_test_interface_ash.cc
index 2df67e8..3e283bc8 100644
--- a/chrome/browser/ash/crosapi/input_method_test_interface_ash.cc
+++ b/chrome/browser/ash/crosapi/input_method_test_interface_ash.cc
@@ -42,7 +42,8 @@
 bool HasCapability(const base::StringPiece capability) {
   return capability == kInputMethodTestCapabilitySendKeyModifiers ||
          capability == kInputMethodTestCapabilityConfirmComposition ||
-         capability == kInputMethodTestCapabilityAlwaysConfirmComposition;
+         capability == kInputMethodTestCapabilityAlwaysConfirmComposition ||
+         capability == kInputMethodTestCapabilityDeleteSurroundingText;
 }
 
 }  // namespace
@@ -210,6 +211,15 @@
   std::move(callback).Run();
 }
 
+void InputMethodTestInterfaceAsh::DeleteSurroundingText(
+    uint32_t length_before_selection,
+    uint32_t length_after_selection,
+    DeleteSurroundingTextCallback callback) {
+  text_input_target_->DeleteSurroundingText(length_before_selection,
+                                            length_after_selection);
+  std::move(callback).Run();
+}
+
 void InputMethodTestInterfaceAsh::OnFocus() {
   focus_callbacks_.Notify();
 }
diff --git a/chrome/browser/ash/crosapi/input_method_test_interface_ash.h b/chrome/browser/ash/crosapi/input_method_test_interface_ash.h
index d81aee2..e5f5bf4 100644
--- a/chrome/browser/ash/crosapi/input_method_test_interface_ash.h
+++ b/chrome/browser/ash/crosapi/input_method_test_interface_ash.h
@@ -93,6 +93,9 @@
   void HasCapabilities(const std::vector<std::string>& capabilities,
                        HasCapabilitiesCallback callback) override;
   void ConfirmComposition(ConfirmCompositionCallback callback) override;
+  void DeleteSurroundingText(uint32_t length_before_selection,
+                             uint32_t length_after_selection,
+                             DeleteSurroundingTextCallback callback) override;
 
   // FakeTextInputMethod::Observer:
   void OnFocus() override;
diff --git a/chrome/browser/lacros/input_method_lacros_browsertest.cc b/chrome/browser/lacros/input_method_lacros_browsertest.cc
index 209af8e1..efba579 100644
--- a/chrome/browser/lacros/input_method_lacros_browsertest.cc
+++ b/chrome/browser/lacros/input_method_lacros_browsertest.cc
@@ -1337,6 +1337,160 @@
 }
 
 IN_PROC_BROWSER_TEST_P(InputMethodLacrosBrowserTest,
+                       DeleteSurroundingTextAtEnd) {
+  mojo::Remote<InputMethodTestInterface> input_method =
+      BindInputMethodTestInterface(
+          GetParam(),
+          {InputMethodTestInterface::MethodMinVersions::kWaitForFocusMinVersion,
+           InputMethodTestInterface::MethodMinVersions::
+               kSetCompositionMinVersion,
+           InputMethodTestInterface::MethodMinVersions::
+               kWaitForNextSurroundingTextChangeMinVersion},
+          {kInputMethodTestCapabilityDeleteSurroundingText});
+  if (!input_method.is_bound()) {
+    GTEST_SKIP() << "Unsupported ash version";
+  }
+  const std::string id = RenderAutofocusedInputFieldInLacros(browser());
+  ASSERT_TRUE(SetInputFieldText(GetActiveWebContents(browser()), id, "abcd",
+                                gfx::Range(4)));
+  InputMethodTestInterfaceAsyncWaiter input_method_async_waiter(
+      input_method.get());
+  input_method_async_waiter.WaitForFocus();
+
+  WaitUntilSurroundingTextIs(input_method_async_waiter, "abcd", gfx::Range(4));
+  input_method_async_waiter.DeleteSurroundingText(1, 0);
+  EXPECT_TRUE(WaitUntilInputFieldHasText(GetActiveWebContents(browser()), id,
+                                         "abc", gfx::Range(3)));
+
+  WaitUntilSurroundingTextIs(input_method_async_waiter, "abc", gfx::Range(3));
+  input_method_async_waiter.DeleteSurroundingText(2, 0);
+  EXPECT_TRUE(WaitUntilInputFieldHasText(GetActiveWebContents(browser()), id,
+                                         "a", gfx::Range(1)));
+}
+
+IN_PROC_BROWSER_TEST_P(InputMethodLacrosBrowserTest,
+                       DeleteSurroundingTextAtBeginning) {
+  mojo::Remote<InputMethodTestInterface> input_method =
+      BindInputMethodTestInterface(
+          GetParam(),
+          {InputMethodTestInterface::MethodMinVersions::kWaitForFocusMinVersion,
+           InputMethodTestInterface::MethodMinVersions::
+               kSetCompositionMinVersion,
+           InputMethodTestInterface::MethodMinVersions::
+               kWaitForNextSurroundingTextChangeMinVersion},
+          {kInputMethodTestCapabilityDeleteSurroundingText});
+  if (!input_method.is_bound()) {
+    GTEST_SKIP() << "Unsupported ash version";
+  }
+  const std::string id = RenderAutofocusedInputFieldInLacros(browser());
+  ASSERT_TRUE(SetInputFieldText(GetActiveWebContents(browser()), id, "abcd",
+                                gfx::Range(0)));
+  InputMethodTestInterfaceAsyncWaiter input_method_async_waiter(
+      input_method.get());
+  input_method_async_waiter.WaitForFocus();
+
+  WaitUntilSurroundingTextIs(input_method_async_waiter, "abcd", gfx::Range(0));
+  input_method_async_waiter.DeleteSurroundingText(0, 1);
+  EXPECT_TRUE(WaitUntilInputFieldHasText(GetActiveWebContents(browser()), id,
+                                         "bcd", gfx::Range(0)));
+
+  WaitUntilSurroundingTextIs(input_method_async_waiter, "bcd", gfx::Range(0));
+  input_method_async_waiter.DeleteSurroundingText(0, 2);
+  EXPECT_TRUE(WaitUntilInputFieldHasText(GetActiveWebContents(browser()), id,
+                                         "d", gfx::Range(0)));
+}
+
+IN_PROC_BROWSER_TEST_P(InputMethodLacrosBrowserTest,
+                       DeleteSurroundingTextInMiddle) {
+  mojo::Remote<InputMethodTestInterface> input_method =
+      BindInputMethodTestInterface(
+          GetParam(),
+          {InputMethodTestInterface::MethodMinVersions::kWaitForFocusMinVersion,
+           InputMethodTestInterface::MethodMinVersions::
+               kSetCompositionMinVersion,
+           InputMethodTestInterface::MethodMinVersions::
+               kWaitForNextSurroundingTextChangeMinVersion},
+          {kInputMethodTestCapabilityDeleteSurroundingText});
+  if (!input_method.is_bound()) {
+    GTEST_SKIP() << "Unsupported ash version";
+  }
+  const std::string id = RenderAutofocusedInputFieldInLacros(browser());
+  ASSERT_TRUE(SetInputFieldText(GetActiveWebContents(browser()), id, "abcd",
+                                gfx::Range(2)));
+  InputMethodTestInterfaceAsyncWaiter input_method_async_waiter(
+      input_method.get());
+  input_method_async_waiter.WaitForFocus();
+
+  WaitUntilSurroundingTextIs(input_method_async_waiter, "abcd", gfx::Range(2));
+  input_method_async_waiter.DeleteSurroundingText(1, 1);
+  EXPECT_TRUE(WaitUntilInputFieldHasText(GetActiveWebContents(browser()), id,
+                                         "ad", gfx::Range(1)));
+
+  WaitUntilSurroundingTextIs(input_method_async_waiter, "ad", gfx::Range(1));
+  input_method_async_waiter.DeleteSurroundingText(1, 1);
+  EXPECT_TRUE(WaitUntilInputFieldHasText(GetActiveWebContents(browser()), id,
+                                         "", gfx::Range(0)));
+}
+
+IN_PROC_BROWSER_TEST_P(
+    InputMethodLacrosBrowserTest,
+    DeleteSurroundingTextInvalidStillDeletesWithLengthCappedAtStart) {
+  mojo::Remote<InputMethodTestInterface> input_method =
+      BindInputMethodTestInterface(
+          GetParam(),
+          {InputMethodTestInterface::MethodMinVersions::kWaitForFocusMinVersion,
+           InputMethodTestInterface::MethodMinVersions::
+               kSetCompositionMinVersion,
+           InputMethodTestInterface::MethodMinVersions::
+               kWaitForNextSurroundingTextChangeMinVersion},
+          {kInputMethodTestCapabilityDeleteSurroundingText});
+  if (!input_method.is_bound()) {
+    GTEST_SKIP() << "Unsupported ash version";
+  }
+  const std::string id = RenderAutofocusedInputFieldInLacros(browser());
+  ASSERT_TRUE(SetInputFieldText(GetActiveWebContents(browser()), id, "abcd",
+                                gfx::Range(2)));
+  InputMethodTestInterfaceAsyncWaiter input_method_async_waiter(
+      input_method.get());
+  input_method_async_waiter.WaitForFocus();
+
+  WaitUntilSurroundingTextIs(input_method_async_waiter, "abcd", gfx::Range(2));
+  input_method_async_waiter.DeleteSurroundingText(3, 1);
+
+  EXPECT_TRUE(WaitUntilInputFieldHasText(GetActiveWebContents(browser()), id,
+                                         "d", gfx::Range(0)));
+}
+
+IN_PROC_BROWSER_TEST_P(
+    InputMethodLacrosBrowserTest,
+    DeleteSurroundingTextInvalidStillDeletesWithLengthCappedAtEnd) {
+  mojo::Remote<InputMethodTestInterface> input_method =
+      BindInputMethodTestInterface(
+          GetParam(),
+          {InputMethodTestInterface::MethodMinVersions::kWaitForFocusMinVersion,
+           InputMethodTestInterface::MethodMinVersions::
+               kSetCompositionMinVersion,
+           InputMethodTestInterface::MethodMinVersions::
+               kWaitForNextSurroundingTextChangeMinVersion},
+          {kInputMethodTestCapabilityDeleteSurroundingText});
+  if (!input_method.is_bound()) {
+    GTEST_SKIP() << "Unsupported ash version";
+  }
+  const std::string id = RenderAutofocusedInputFieldInLacros(browser());
+  ASSERT_TRUE(SetInputFieldText(GetActiveWebContents(browser()), id, "abcd",
+                                gfx::Range(2)));
+  InputMethodTestInterfaceAsyncWaiter input_method_async_waiter(
+      input_method.get());
+  input_method_async_waiter.WaitForFocus();
+
+  WaitUntilSurroundingTextIs(input_method_async_waiter, "abcd", gfx::Range(2));
+  input_method_async_waiter.DeleteSurroundingText(1, 3);
+
+  EXPECT_TRUE(WaitUntilInputFieldHasText(GetActiveWebContents(browser()), id,
+                                         "a", gfx::Range(1)));
+}
+
+IN_PROC_BROWSER_TEST_P(InputMethodLacrosBrowserTest,
                        ConfirmCompositionWithNoSelectionAndNoComposition) {
   mojo::Remote<InputMethodTestInterface> input_method =
       BindInputMethodTestInterface(
diff --git a/chromeos/crosapi/cpp/input_method_test_interface_constants.h b/chromeos/crosapi/cpp/input_method_test_interface_constants.h
index 13c200e..66cd69d 100644
--- a/chromeos/crosapi/cpp/input_method_test_interface_constants.h
+++ b/chromeos/crosapi/cpp/input_method_test_interface_constants.h
@@ -26,6 +26,10 @@
     kInputMethodTestCapabilityAlwaysConfirmComposition =
         "AlwaysConfirmComposition";
 
+COMPONENT_EXPORT(CROSAPI)
+inline constexpr base::StringPiece
+    kInputMethodTestCapabilityDeleteSurroundingText = "DeleteSurroundingText";
+
 }  // namespace crosapi
 
 #endif  // CHROMEOS_CROSAPI_CPP_INPUT_METHOD_TEST_INTERFACE_CONSTANTS_H_
diff --git a/chromeos/crosapi/mojom/test_controller.mojom b/chromeos/crosapi/mojom/test_controller.mojom
index 8f09498..a32d4a2 100644
--- a/chromeos/crosapi/mojom/test_controller.mojom
+++ b/chromeos/crosapi/mojom/test_controller.mojom
@@ -170,8 +170,8 @@
 
 // This interface is implemented by Ash-Chrome.
 // It enables tests in Lacros-Chrome to send commands as an input method.
-// Next version: 7
-// Next method id: 8
+// Next version: 8
+// Next method id: 9
 [Stable, Uuid="c214f4f5-c583-44d1-9547-bb2456d9e70b"]
 interface InputMethodTestInterface {
   // Calls the callback when the input method has focused on some input field.
@@ -232,6 +232,10 @@
 
   // Calls `ash::InputMethodAsh::ConfirmCompositionText`.
   [MinVersion=6] ConfirmComposition@7() => ();
+
+  // Calls `ash::InputMethodAsh::DeleteSurroundingText`.
+  [MinVersion=7] DeleteSurroundingText@8(uint32 length_before_selection,
+                                         uint32 length_after_selection) => ();
 };
 
 // This interface is implemented by Ash-Chrome.