Add TextInputModel unittests (#18411)
* Add missing return values to TextInputModel::MoveCursorToBeginning and TextInputModel::MoveCursorToEnd
* Add TextInputModel unittests
diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter
index 4aad0ab..a9daedd 100755
--- a/ci/licenses_golden/licenses_flutter
+++ b/ci/licenses_golden/licenses_flutter
@@ -831,6 +831,7 @@
FILE: ../../../flutter/shell/platform/common/cpp/public/flutter_plugin_registrar.h
FILE: ../../../flutter/shell/platform/common/cpp/text_input_model.cc
FILE: ../../../flutter/shell/platform/common/cpp/text_input_model.h
+FILE: ../../../flutter/shell/platform/common/cpp/text_input_model_unittests.cc
FILE: ../../../flutter/shell/platform/darwin/common/buffer_conversions.h
FILE: ../../../flutter/shell/platform/darwin/common/buffer_conversions.mm
FILE: ../../../flutter/shell/platform/darwin/common/command_line.h
diff --git a/shell/platform/common/cpp/BUILD.gn b/shell/platform/common/cpp/BUILD.gn
index f3bcde6..a58bdbe 100644
--- a/shell/platform/common/cpp/BUILD.gn
+++ b/shell/platform/common/cpp/BUILD.gn
@@ -111,6 +111,7 @@
sources = [
"json_message_codec_unittests.cc",
"json_method_codec_unittests.cc",
+ "text_input_model_unittests.cc",
]
deps = [
diff --git a/shell/platform/common/cpp/text_input_model.cc b/shell/platform/common/cpp/text_input_model.cc
index 0a92dc7..49c11ed 100644
--- a/shell/platform/common/cpp/text_input_model.cc
+++ b/shell/platform/common/cpp/text_input_model.cc
@@ -113,14 +113,24 @@
return false;
}
-void TextInputModel::MoveCursorToBeginning() {
+bool TextInputModel::MoveCursorToBeginning() {
+ if (selection_base_ == text_.begin() && selection_extent_ == text_.begin())
+ return false;
+
selection_base_ = text_.begin();
selection_extent_ = text_.begin();
+
+ return true;
}
-void TextInputModel::MoveCursorToEnd() {
+bool TextInputModel::MoveCursorToEnd() {
+ if (selection_base_ == text_.end() && selection_extent_ == text_.end())
+ return false;
+
selection_base_ = text_.end();
selection_extent_ = text_.end();
+
+ return true;
}
bool TextInputModel::MoveCursorForward() {
diff --git a/shell/platform/common/cpp/text_input_model.h b/shell/platform/common/cpp/text_input_model.h
index ac6cf8d..5444283 100644
--- a/shell/platform/common/cpp/text_input_model.h
+++ b/shell/platform/common/cpp/text_input_model.h
@@ -70,12 +70,12 @@
// Attempts to move the cursor to the beginning.
//
// Returns true if the cursor could be moved.
- void MoveCursorToBeginning();
+ bool MoveCursorToBeginning();
// Attempts to move the cursor to the back.
//
// Returns true if the cursor could be moved.
- void MoveCursorToEnd();
+ bool MoveCursorToEnd();
// Get the current text
std::string GetText() const;
diff --git a/shell/platform/common/cpp/text_input_model_unittests.cc b/shell/platform/common/cpp/text_input_model_unittests.cc
new file mode 100644
index 0000000..7853015
--- /dev/null
+++ b/shell/platform/common/cpp/text_input_model_unittests.cc
@@ -0,0 +1,383 @@
+// Copyright 2013 The Flutter 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 "flutter/shell/platform/common/cpp/text_input_model.h"
+
+#include <limits>
+#include <map>
+#include <vector>
+
+#include "gtest/gtest.h"
+
+namespace flutter {
+
+TEST(TextInputModel, InputTypeAndAction) {
+ auto model = std::make_unique<TextInputModel>("INPUT_TYPE", "INPUT_ACTION");
+ EXPECT_STREQ(model->input_type().c_str(), "INPUT_TYPE");
+ EXPECT_STREQ(model->input_action().c_str(), "INPUT_ACTION");
+}
+
+TEST(TextInputModel, SetEditingStateStart) {
+ auto model = std::make_unique<TextInputModel>("", "");
+ EXPECT_TRUE(model->SetEditingState(0, 0, "ABCDE"));
+ EXPECT_EQ(model->selection_base(), 0);
+ EXPECT_EQ(model->selection_extent(), 0);
+ EXPECT_STREQ(model->GetText().c_str(), "ABCDE");
+}
+
+TEST(TextInputModel, SetEditingMiddle) {
+ auto model = std::make_unique<TextInputModel>("", "");
+ EXPECT_TRUE(model->SetEditingState(2, 2, "ABCDE"));
+ EXPECT_EQ(model->selection_base(), 2);
+ EXPECT_EQ(model->selection_extent(), 2);
+ EXPECT_STREQ(model->GetText().c_str(), "ABCDE");
+}
+
+TEST(TextInputModel, SetEditingStateEnd) {
+ auto model = std::make_unique<TextInputModel>("", "");
+ EXPECT_TRUE(model->SetEditingState(5, 5, "ABCDE"));
+ EXPECT_EQ(model->selection_base(), 5);
+ EXPECT_EQ(model->selection_extent(), 5);
+ EXPECT_STREQ(model->GetText().c_str(), "ABCDE");
+}
+
+TEST(TextInputModel, SetEditingStateSelection) {
+ auto model = std::make_unique<TextInputModel>("", "");
+ EXPECT_TRUE(model->SetEditingState(1, 4, "ABCDE"));
+ EXPECT_EQ(model->selection_base(), 1);
+ EXPECT_EQ(model->selection_extent(), 4);
+ EXPECT_STREQ(model->GetText().c_str(), "ABCDE");
+}
+
+TEST(TextInputModel, SetEditingStateReverseSelection) {
+ auto model = std::make_unique<TextInputModel>("", "");
+ EXPECT_FALSE(model->SetEditingState(3, 1, "ABCDE"));
+}
+
+TEST(TextInputModel, SetEditingStateOutsideString) {
+ auto model = std::make_unique<TextInputModel>("", "");
+ EXPECT_FALSE(model->SetEditingState(4, 6, "ABCDE"));
+ EXPECT_FALSE(model->SetEditingState(5, 6, "ABCDE"));
+ EXPECT_FALSE(model->SetEditingState(6, 6, "ABCDE"));
+}
+
+TEST(TextInputModel, SetEditingStateWideCharacters) {
+ auto model = std::make_unique<TextInputModel>("", "");
+ EXPECT_TRUE(model->SetEditingState(0, 0, "πππ€ͺπ§"));
+ EXPECT_EQ(model->selection_base(), 0);
+ EXPECT_EQ(model->selection_extent(), 0);
+ EXPECT_STREQ(model->GetText().c_str(), "πππ€ͺπ§");
+}
+
+TEST(TextInputModel, AddCodePoint) {
+ auto model = std::make_unique<TextInputModel>("", "");
+ model->AddCodePoint('A');
+ model->AddCodePoint('B');
+ model->AddCodePoint(0x1f604);
+ model->AddCodePoint('D');
+ model->AddCodePoint('E');
+ EXPECT_EQ(model->selection_base(), 6);
+ EXPECT_EQ(model->selection_extent(), 6);
+ EXPECT_STREQ(model->GetText().c_str(), "ABπDE");
+}
+
+TEST(TextInputModel, AddCodePointSelection) {
+ auto model = std::make_unique<TextInputModel>("", "");
+ EXPECT_TRUE(model->SetEditingState(1, 4, "ABCDE"));
+ model->AddCodePoint('x');
+ EXPECT_EQ(model->selection_base(), 2);
+ EXPECT_EQ(model->selection_extent(), 2);
+ EXPECT_STREQ(model->GetText().c_str(), "AxE");
+}
+
+TEST(TextInputModel, AddCodePointSelectionWideCharacter) {
+ auto model = std::make_unique<TextInputModel>("", "");
+ EXPECT_TRUE(model->SetEditingState(1, 4, "ABCDE"));
+ model->AddCodePoint(0x1f604);
+ EXPECT_EQ(model->selection_base(), 3);
+ EXPECT_EQ(model->selection_extent(), 3);
+ EXPECT_STREQ(model->GetText().c_str(), "AπE");
+}
+
+TEST(TextInputModel, AddText) {
+ auto model = std::make_unique<TextInputModel>("", "");
+ model->AddText(u"ABCDE");
+ model->AddText(u"π");
+ model->AddText(u"FGHIJ");
+ EXPECT_EQ(model->selection_base(), 12);
+ EXPECT_EQ(model->selection_extent(), 12);
+ EXPECT_STREQ(model->GetText().c_str(), "ABCDEπFGHIJ");
+}
+
+TEST(TextInputModel, AddTextSelection) {
+ auto model = std::make_unique<TextInputModel>("", "");
+ EXPECT_TRUE(model->SetEditingState(1, 4, "ABCDE"));
+ model->AddText(u"xy");
+ EXPECT_EQ(model->selection_base(), 3);
+ EXPECT_EQ(model->selection_extent(), 3);
+ EXPECT_STREQ(model->GetText().c_str(), "AxyE");
+}
+
+TEST(TextInputModel, AddTextSelectionWideCharacter) {
+ auto model = std::make_unique<TextInputModel>("", "");
+ EXPECT_TRUE(model->SetEditingState(1, 4, "ABCDE"));
+ model->AddText(u"ππ");
+ EXPECT_EQ(model->selection_base(), 5);
+ EXPECT_EQ(model->selection_extent(), 5);
+ EXPECT_STREQ(model->GetText().c_str(), "AππE");
+}
+
+TEST(TextInputModel, DeleteStart) {
+ auto model = std::make_unique<TextInputModel>("", "");
+ EXPECT_TRUE(model->SetEditingState(0, 0, "ABCDE"));
+ ASSERT_TRUE(model->Delete());
+ EXPECT_EQ(model->selection_base(), 0);
+ EXPECT_EQ(model->selection_extent(), 0);
+ EXPECT_STREQ(model->GetText().c_str(), "BCDE");
+}
+
+TEST(TextInputModel, DeleteMiddle) {
+ auto model = std::make_unique<TextInputModel>("", "");
+ EXPECT_TRUE(model->SetEditingState(2, 2, "ABCDE"));
+ ASSERT_TRUE(model->Delete());
+ EXPECT_EQ(model->selection_base(), 2);
+ EXPECT_EQ(model->selection_extent(), 2);
+ EXPECT_STREQ(model->GetText().c_str(), "ABDE");
+}
+
+TEST(TextInputModel, DeleteEnd) {
+ auto model = std::make_unique<TextInputModel>("", "");
+ EXPECT_TRUE(model->SetEditingState(5, 5, "ABCDE"));
+ ASSERT_FALSE(model->Delete());
+ EXPECT_EQ(model->selection_base(), 5);
+ EXPECT_EQ(model->selection_extent(), 5);
+ EXPECT_STREQ(model->GetText().c_str(), "ABCDE");
+}
+
+TEST(TextInputModel, DeleteWideCharacters) {
+ auto model = std::make_unique<TextInputModel>("", "");
+ EXPECT_TRUE(model->SetEditingState(4, 4, "πππ€ͺπ§"));
+ ASSERT_TRUE(model->Delete());
+ EXPECT_EQ(model->selection_base(), 4);
+ EXPECT_EQ(model->selection_extent(), 4);
+ EXPECT_STREQ(model->GetText().c_str(), "πππ§");
+}
+
+TEST(TextInputModel, DeleteSelection) {
+ auto model = std::make_unique<TextInputModel>("", "");
+ EXPECT_TRUE(model->SetEditingState(1, 4, "ABCDE"));
+ ASSERT_TRUE(model->Delete());
+ EXPECT_EQ(model->selection_base(), 1);
+ EXPECT_EQ(model->selection_extent(), 1);
+ EXPECT_STREQ(model->GetText().c_str(), "AE");
+}
+
+TEST(TextInputModel, BackspaceStart) {
+ auto model = std::make_unique<TextInputModel>("", "");
+ EXPECT_TRUE(model->SetEditingState(0, 0, "ABCDE"));
+ ASSERT_FALSE(model->Backspace());
+ EXPECT_EQ(model->selection_base(), 0);
+ EXPECT_EQ(model->selection_extent(), 0);
+ EXPECT_STREQ(model->GetText().c_str(), "ABCDE");
+}
+
+TEST(TextInputModel, BackspaceMiddle) {
+ auto model = std::make_unique<TextInputModel>("", "");
+ EXPECT_TRUE(model->SetEditingState(2, 2, "ABCDE"));
+ ASSERT_TRUE(model->Backspace());
+ EXPECT_EQ(model->selection_base(), 1);
+ EXPECT_EQ(model->selection_extent(), 1);
+ EXPECT_STREQ(model->GetText().c_str(), "ACDE");
+}
+
+TEST(TextInputModel, BackspaceEnd) {
+ auto model = std::make_unique<TextInputModel>("", "");
+ EXPECT_TRUE(model->SetEditingState(5, 5, "ABCDE"));
+ ASSERT_TRUE(model->Backspace());
+ EXPECT_EQ(model->selection_base(), 4);
+ EXPECT_EQ(model->selection_extent(), 4);
+ EXPECT_STREQ(model->GetText().c_str(), "ABCD");
+}
+
+TEST(TextInputModel, BackspaceWideCharacters) {
+ auto model = std::make_unique<TextInputModel>("", "");
+ EXPECT_TRUE(model->SetEditingState(4, 4, "πππ€ͺπ§"));
+ ASSERT_TRUE(model->Backspace());
+ EXPECT_EQ(model->selection_base(), 2);
+ EXPECT_EQ(model->selection_extent(), 2);
+ EXPECT_STREQ(model->GetText().c_str(), "ππ€ͺπ§");
+}
+
+TEST(TextInputModel, BackspaceSelection) {
+ auto model = std::make_unique<TextInputModel>("", "");
+ EXPECT_TRUE(model->SetEditingState(1, 4, "ABCDE"));
+ ASSERT_TRUE(model->Delete());
+ EXPECT_EQ(model->selection_base(), 1);
+ EXPECT_EQ(model->selection_extent(), 1);
+ EXPECT_STREQ(model->GetText().c_str(), "AE");
+}
+
+TEST(TextInputModel, MoveCursorForwardStart) {
+ auto model = std::make_unique<TextInputModel>("", "");
+ EXPECT_TRUE(model->SetEditingState(0, 0, "ABCDE"));
+ EXPECT_TRUE(model->MoveCursorForward());
+ EXPECT_EQ(model->selection_base(), 1);
+ EXPECT_EQ(model->selection_extent(), 1);
+ EXPECT_STREQ(model->GetText().c_str(), "ABCDE");
+}
+
+TEST(TextInputModel, MoveCursorForwardMiddle) {
+ auto model = std::make_unique<TextInputModel>("", "");
+ EXPECT_TRUE(model->SetEditingState(2, 2, "ABCDE"));
+ EXPECT_TRUE(model->MoveCursorForward());
+ EXPECT_EQ(model->selection_base(), 3);
+ EXPECT_EQ(model->selection_extent(), 3);
+ EXPECT_STREQ(model->GetText().c_str(), "ABCDE");
+}
+
+TEST(TextInputModel, MoveCursorForwardEnd) {
+ auto model = std::make_unique<TextInputModel>("", "");
+ EXPECT_TRUE(model->SetEditingState(5, 5, "ABCDE"));
+ EXPECT_FALSE(model->MoveCursorForward());
+ EXPECT_EQ(model->selection_base(), 5);
+ EXPECT_EQ(model->selection_extent(), 5);
+ EXPECT_STREQ(model->GetText().c_str(), "ABCDE");
+}
+
+TEST(TextInputModel, MoveCursorForwardWideCharacters) {
+ auto model = std::make_unique<TextInputModel>("", "");
+ EXPECT_TRUE(model->SetEditingState(4, 4, "πππ€ͺπ§"));
+ ASSERT_TRUE(model->MoveCursorForward());
+ EXPECT_EQ(model->selection_base(), 6);
+ EXPECT_EQ(model->selection_extent(), 6);
+ EXPECT_STREQ(model->GetText().c_str(), "πππ€ͺπ§");
+}
+
+TEST(TextInputModel, MoveCursorForwardSelection) {
+ auto model = std::make_unique<TextInputModel>("", "");
+ EXPECT_TRUE(model->SetEditingState(1, 4, "ABCDE"));
+ EXPECT_TRUE(model->MoveCursorForward());
+ EXPECT_EQ(model->selection_base(), 4);
+ EXPECT_EQ(model->selection_extent(), 4);
+ EXPECT_STREQ(model->GetText().c_str(), "ABCDE");
+}
+
+TEST(TextInputModel, MoveCursorBackStart) {
+ auto model = std::make_unique<TextInputModel>("", "");
+ EXPECT_TRUE(model->SetEditingState(0, 0, "ABCDE"));
+ EXPECT_FALSE(model->MoveCursorBack());
+ EXPECT_EQ(model->selection_base(), 0);
+ EXPECT_EQ(model->selection_extent(), 0);
+ EXPECT_STREQ(model->GetText().c_str(), "ABCDE");
+}
+
+TEST(TextInputModel, MoveCursorBackMiddle) {
+ auto model = std::make_unique<TextInputModel>("", "");
+ model->SetEditingState(2, 2, "ABCDE");
+ EXPECT_TRUE(model->MoveCursorBack());
+ EXPECT_EQ(model->selection_base(), 1);
+ EXPECT_EQ(model->selection_extent(), 1);
+ EXPECT_STREQ(model->GetText().c_str(), "ABCDE");
+}
+
+TEST(TextInputModel, MoveCursorBackEnd) {
+ auto model = std::make_unique<TextInputModel>("", "");
+ model->SetEditingState(5, 5, "ABCDE");
+ EXPECT_TRUE(model->MoveCursorBack());
+ EXPECT_EQ(model->selection_base(), 4);
+ EXPECT_EQ(model->selection_extent(), 4);
+ EXPECT_STREQ(model->GetText().c_str(), "ABCDE");
+}
+
+TEST(TextInputModel, MoveCursorBackWideCharacters) {
+ auto model = std::make_unique<TextInputModel>("", "");
+ EXPECT_TRUE(model->SetEditingState(4, 4, "πππ€ͺπ§"));
+ ASSERT_TRUE(model->MoveCursorBack());
+ EXPECT_EQ(model->selection_base(), 2);
+ EXPECT_EQ(model->selection_extent(), 2);
+ EXPECT_STREQ(model->GetText().c_str(), "πππ€ͺπ§");
+}
+
+TEST(TextInputModel, MoveCursorBackSelection) {
+ auto model = std::make_unique<TextInputModel>("", "");
+ model->SetEditingState(1, 4, "ABCDE");
+ EXPECT_TRUE(model->MoveCursorBack());
+ EXPECT_EQ(model->selection_base(), 1);
+ EXPECT_EQ(model->selection_extent(), 1);
+ EXPECT_STREQ(model->GetText().c_str(), "ABCDE");
+}
+
+TEST(TextInputModel, MoveCursorToBeginningStart) {
+ auto model = std::make_unique<TextInputModel>("", "");
+ model->SetEditingState(0, 0, "ABCDE");
+ EXPECT_FALSE(model->MoveCursorToBeginning());
+ EXPECT_EQ(model->selection_base(), 0);
+ EXPECT_EQ(model->selection_extent(), 0);
+ EXPECT_STREQ(model->GetText().c_str(), "ABCDE");
+}
+
+TEST(TextInputModel, MoveCursorToBeginningMiddle) {
+ auto model = std::make_unique<TextInputModel>("", "");
+ model->SetEditingState(2, 2, "ABCDE");
+ EXPECT_TRUE(model->MoveCursorToBeginning());
+ EXPECT_EQ(model->selection_base(), 0);
+ EXPECT_EQ(model->selection_extent(), 0);
+ EXPECT_STREQ(model->GetText().c_str(), "ABCDE");
+}
+
+TEST(TextInputModel, MoveCursorToBeginningEnd) {
+ auto model = std::make_unique<TextInputModel>("", "");
+ model->SetEditingState(5, 5, "ABCDE");
+ EXPECT_TRUE(model->MoveCursorToBeginning());
+ EXPECT_EQ(model->selection_base(), 0);
+ EXPECT_EQ(model->selection_extent(), 0);
+ EXPECT_STREQ(model->GetText().c_str(), "ABCDE");
+}
+
+TEST(TextInputModel, MoveCursorToBeginningSelection) {
+ auto model = std::make_unique<TextInputModel>("", "");
+ model->SetEditingState(1, 4, "ABCDE");
+ EXPECT_TRUE(model->MoveCursorToBeginning());
+ EXPECT_EQ(model->selection_base(), 0);
+ EXPECT_EQ(model->selection_extent(), 0);
+ EXPECT_STREQ(model->GetText().c_str(), "ABCDE");
+}
+
+TEST(TextInputModel, MoveCursorToEndStart) {
+ auto model = std::make_unique<TextInputModel>("", "");
+ model->SetEditingState(0, 0, "ABCDE");
+ EXPECT_TRUE(model->MoveCursorToEnd());
+ EXPECT_EQ(model->selection_base(), 5);
+ EXPECT_EQ(model->selection_extent(), 5);
+ EXPECT_STREQ(model->GetText().c_str(), "ABCDE");
+}
+
+TEST(TextInputModel, MoveCursorToEndMiddle) {
+ auto model = std::make_unique<TextInputModel>("", "");
+ model->SetEditingState(2, 2, "ABCDE");
+ EXPECT_TRUE(model->MoveCursorToEnd());
+ EXPECT_EQ(model->selection_base(), 5);
+ EXPECT_EQ(model->selection_extent(), 5);
+ EXPECT_STREQ(model->GetText().c_str(), "ABCDE");
+}
+
+TEST(TextInputModel, MoveCursorToEndEnd) {
+ auto model = std::make_unique<TextInputModel>("", "");
+ model->SetEditingState(5, 5, "ABCDE");
+ EXPECT_FALSE(model->MoveCursorToEnd());
+ EXPECT_EQ(model->selection_base(), 5);
+ EXPECT_EQ(model->selection_extent(), 5);
+ EXPECT_STREQ(model->GetText().c_str(), "ABCDE");
+}
+
+TEST(TextInputModel, MoveCursorToEndSelection) {
+ auto model = std::make_unique<TextInputModel>("", "");
+ model->SetEditingState(1, 4, "ABCDE");
+ EXPECT_TRUE(model->MoveCursorToEnd());
+ EXPECT_EQ(model->selection_base(), 5);
+ EXPECT_EQ(model->selection_extent(), 5);
+ EXPECT_STREQ(model->GetText().c_str(), "ABCDE");
+}
+
+} // namespace flutter