blob: c6b543e9ce6fcbdacf42511b285f6921bf0000a8 [file] [log] [blame]
// Copyright 2025 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#import "ios/chrome/browser/omnibox/model/omnibox_text_controller.h"
#import "base/test/task_environment.h"
#import "components/omnibox/browser/autocomplete_controller.h"
#import "components/omnibox/browser/autocomplete_provider_client.h"
#import "components/omnibox/browser/omnibox_prefs.h"
#import "components/omnibox/browser/test_location_bar_model.h"
#import "components/omnibox/browser/test_omnibox_client.h"
#import "components/prefs/testing_pref_service.h"
#import "components/sync_preferences/testing_pref_service_syncable.h"
#import "ios/chrome/browser/omnibox/model/omnibox_autocomplete_controller.h"
#import "ios/chrome/browser/omnibox/model/omnibox_text_model.h"
#import "ios/chrome/browser/shared/model/prefs/browser_prefs.h"
#import "ios/chrome/browser/shared/model/prefs/pref_names.h"
#import "ios/chrome/test/testing_application_context.h"
#import "testing/gmock/include/gmock/gmock.h"
#import "testing/gtest/include/gtest/gtest.h"
#import "testing/platform_test.h"
// Mocking the text controller to not rely on the textfield view.
@interface TestOmniboxTextController : OmniboxTextController
@end
@implementation TestOmniboxTextController {
std::u16string text_;
}
- (std::u16string)displayedText {
return text_;
}
- (void)setWindowText:(const std::u16string&)text
caretPos:(size_t)caretPos
startAutocomplete:(BOOL)startAutocomplete
notifyTextChanged:(BOOL)notifyTextChanged {
[super setWindowText:text
caretPos:caretPos
startAutocomplete:startAutocomplete
notifyTextChanged:notifyTextChanged];
text_ = text;
}
- (void)updateAutocompleteIfTextChanged:(const std::u16string&)userText
autocompletion:
(const std::u16string&)inlineAutocomplete {
[super updateAutocompleteIfTextChanged:userText
autocompletion:inlineAutocomplete];
text_ = userText + inlineAutocomplete;
}
@end
class OmniboxTextControllerTest : public PlatformTest {
public:
OmniboxTextControllerTest() {
omnibox_client_ = std::make_unique<TestOmniboxClient>();
omnibox::RegisterProfilePrefs(
static_cast<sync_preferences::TestingPrefServiceSyncable*>(
classifier_pref_service())
->registry());
omnibox_text_model_ =
std::make_unique<OmniboxTextModel>(omnibox_client_.get());
local_state_ = std::make_unique<TestingPrefServiceSimple>();
RegisterLocalStatePrefs(local_state_->registry());
TestingApplicationContext::GetGlobal()->SetLocalState(local_state_.get());
omnibox_autocomplete_controller_ = [[OmniboxAutocompleteController alloc]
initWithOmniboxClient:omnibox_client_.get()
omniboxTextModel:omnibox_text_model_.get()];
omnibox_text_controller_ = [[TestOmniboxTextController alloc]
initWithOmniboxClient:omnibox_client_.get()
omniboxTextModel:omnibox_text_model_.get()
inLensOverlay:NO];
omnibox_text_controller_.omniboxAutocompleteController =
omnibox_autocomplete_controller_;
}
~OmniboxTextControllerTest() override {
[omnibox_text_controller_ disconnect];
omnibox_text_controller_ = nil;
[omnibox_autocomplete_controller_ disconnect];
omnibox_autocomplete_controller_ = nil;
omnibox_client_.reset();
TestingApplicationContext::GetGlobal()->SetLocalState(nullptr);
local_state_.reset();
}
PrefService* classifier_pref_service() {
return omnibox_client_->autocomplete_classifier()
->autocomplete_controller()
->autocomplete_provider_client()
->GetPrefs();
}
TestLocationBarModel* location_bar_model() {
return omnibox_client_->location_bar_model();
}
bool current_text_is_URL() const {
return !omnibox_text_model_->user_input_in_progress ||
!AutocompleteMatch::IsSearchType(
[omnibox_text_controller_ currentMatch:nullptr].type);
}
protected:
base::test::TaskEnvironment environment_;
OmniboxAutocompleteController* omnibox_autocomplete_controller_;
TestOmniboxTextController* omnibox_text_controller_;
std::unique_ptr<OmniboxTextModel> omnibox_text_model_;
std::unique_ptr<TestOmniboxClient> omnibox_client_;
// Application pref service.
std::unique_ptr<TestingPrefServiceSimple> local_state_;
};
// Tests if the controller updates the inline autocomplete text.
TEST_F(OmniboxTextControllerTest, InlineAutocompleteText) {
EXPECT_EQ(std::u16string(), omnibox_text_model_->inline_autocompletion);
[omnibox_text_controller_ setUserText:u"he"];
[omnibox_text_controller_ onPopupDataChanged:u"llo"
additionalText:std::u16string()
newMatch:{}];
EXPECT_EQ(u"hello", [omnibox_text_controller_ displayedText]);
EXPECT_EQ(u"llo", omnibox_text_model_->inline_autocompletion);
[omnibox_text_controller_ setUserText:u"hel"];
EXPECT_EQ(std::u16string(), omnibox_text_model_->inline_autocompletion);
[omnibox_text_controller_ onPopupDataChanged:u"lo"
additionalText:std::u16string()
newMatch:{}];
EXPECT_EQ(u"hello", [omnibox_text_controller_ displayedText]);
EXPECT_EQ(u"lo", omnibox_text_model_->inline_autocompletion);
[omnibox_text_controller_ revertState];
EXPECT_EQ(std::u16string(), [omnibox_text_controller_ displayedText]);
EXPECT_EQ(std::u16string(), omnibox_text_model_->inline_autocompletion);
[omnibox_text_controller_ setUserText:u"he"];
[omnibox_text_controller_ onPopupDataChanged:u"llo"
additionalText:std::u16string()
newMatch:{}];
EXPECT_EQ(u"hello", [omnibox_text_controller_ displayedText]);
EXPECT_EQ(u"llo", omnibox_text_model_->inline_autocompletion);
}
TEST_F(OmniboxTextControllerTest, CurrentMatch) {
// Test the HTTP case.
{
location_bar_model()->set_url(GURL("http://www.example.com/"));
location_bar_model()->set_url_for_display(u"example.com");
[omnibox_text_controller_ resetDisplayTexts];
[omnibox_text_controller_ revertState];
EXPECT_EQ(u"http://www.example.com/",
[omnibox_text_controller_ displayedText]);
AutocompleteMatch match = [omnibox_text_controller_ currentMatch:nullptr];
EXPECT_EQ(AutocompleteMatchType::URL_WHAT_YOU_TYPED, match.type);
EXPECT_TRUE(current_text_is_URL());
EXPECT_EQ("http://www.example.com/", match.destination_url.spec());
}
// Test that generating a match from an elided HTTPS URL doesn't drop the
// secure scheme.
{
location_bar_model()->set_url(GURL("https://www.google.com/"));
location_bar_model()->set_url_for_display(u"google.com");
[omnibox_text_controller_ resetDisplayTexts];
[omnibox_text_controller_ revertState];
EXPECT_EQ(u"https://www.google.com/",
[omnibox_text_controller_ displayedText]);
AutocompleteMatch match = [omnibox_text_controller_ currentMatch:nullptr];
EXPECT_EQ(AutocompleteMatchType::URL_WHAT_YOU_TYPED, match.type);
EXPECT_TRUE(current_text_is_URL());
// Additionally verify we aren't accidentally dropping the HTTPS scheme.
EXPECT_EQ("https://www.google.com/", match.destination_url.spec());
}
}
TEST_F(OmniboxTextControllerTest, DisplayText) {
location_bar_model()->set_url(GURL("https://www.example.com/"));
location_bar_model()->set_url_for_display(u"example.com");
EXPECT_TRUE([omnibox_text_controller_ resetDisplayTexts]);
[omnibox_text_controller_ revertState];
EXPECT_TRUE(current_text_is_URL());
// iOS OmniboxEditModel always provides the full URL as the OmniboxView
// permanent display text.
EXPECT_EQ(u"https://www.example.com/", omnibox_text_model_->url_for_editing);
EXPECT_EQ(u"https://www.example.com/",
[omnibox_text_controller_ displayedText]);
EXPECT_FALSE(omnibox_text_model_->user_input_in_progress);
EXPECT_EQ(u"https://www.example.com/",
[omnibox_text_controller_ displayedText]);
EXPECT_TRUE(current_text_is_URL());
}