| Index: ios/chrome/browser/ui/omnibox/omnibox_text_field_ios_unittest.mm
|
| diff --git a/ios/chrome/browser/ui/omnibox/omnibox_text_field_ios_unittest.mm b/ios/chrome/browser/ui/omnibox/omnibox_text_field_ios_unittest.mm
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..4b0eddd49942ef1dcfa4388d09ca5e786695a504
|
| --- /dev/null
|
| +++ b/ios/chrome/browser/ui/omnibox/omnibox_text_field_ios_unittest.mm
|
| @@ -0,0 +1,274 @@
|
| +// Copyright 2012 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.
|
| +
|
| +#import "ios/chrome/browser/ui/omnibox/omnibox_text_field_ios.h"
|
| +
|
| +#include "base/command_line.h"
|
| +#include "base/files/file_path.h"
|
| +#include "base/files/file_util.h"
|
| +#include "base/mac/scoped_nsobject.h"
|
| +#include "base/path_service.h"
|
| +#include "base/strings/string_split.h"
|
| +#include "base/strings/sys_string_conversions.h"
|
| +#include "ios/chrome/browser/chrome_paths.h"
|
| +#include "ios/chrome/grit/ios_strings.h"
|
| +#include "testing/gtest_mac.h"
|
| +#include "testing/platform_test.h"
|
| +#include "ui/base/l10n/l10n_util_mac.h"
|
| +
|
| +// A category for making existing methods visible for use in these tests.
|
| +@interface OmniboxTextFieldIOS (VisibleForTesting)
|
| +- (CGRect)rectForDrawTextInRect:(CGRect)rect;
|
| +@end
|
| +
|
| +namespace {
|
| +
|
| +class OmniboxTextFieldIOSTest : public PlatformTest {
|
| + protected:
|
| + void SetUp() override {
|
| + PlatformTest::SetUp();
|
| + // This rect is fairly arbitrary. The text field just needs a non-zero width
|
| + // so that the pre-edit label's text alignment can be tested.
|
| + CGRect rect = CGRectMake(0, 0, 100, 20);
|
| + textfield_.reset([[OmniboxTextFieldIOS alloc] initWithFrame:rect]);
|
| + [[[UIApplication sharedApplication] keyWindow] addSubview:textfield_];
|
| + };
|
| +
|
| + void TearDown() override { [textfield_ removeFromSuperview]; }
|
| +
|
| + BOOL IsCopyUrlInMenu() {
|
| + UIMenuController* menuController = [UIMenuController sharedMenuController];
|
| + NSString* const kTitle = l10n_util::GetNSString(IDS_IOS_COPY_URL);
|
| + for (UIMenuItem* item in menuController.menuItems) {
|
| + if ([item.title isEqual:kTitle])
|
| + return YES;
|
| + }
|
| + return NO;
|
| + };
|
| +
|
| + void ExpectRectEqual(CGRect expectedRect, CGRect actualRect) {
|
| + EXPECT_EQ(expectedRect.origin.x, actualRect.origin.x);
|
| + EXPECT_EQ(expectedRect.origin.y, actualRect.origin.y);
|
| + EXPECT_EQ(expectedRect.size.width, actualRect.size.width);
|
| + EXPECT_EQ(expectedRect.size.height, actualRect.size.height);
|
| + }
|
| +
|
| + // Verifies that the |selectedNSRange| function properly converts from opaque
|
| + // UITextRanges to NSRanges. This function selects blocks of text in the text
|
| + // field and compares the field's actual selected text to the converted
|
| + // NSRange.
|
| + void VerifySelectedNSRanges(NSString* text) {
|
| + // The NSRange conversion mechanism only works when the field is first
|
| + // responder.
|
| + [textfield_ setText:text];
|
| + [textfield_ becomeFirstResponder];
|
| + ASSERT_TRUE([textfield_ isFirstResponder]);
|
| +
|
| + // |i| and |j| hold the start and end offsets of the range that is currently
|
| + // being tested. This function iterates through all possible combinations
|
| + // of |i| and |j|.
|
| + NSInteger i = 0;
|
| + NSInteger j = i + 1;
|
| + UITextPosition* beginning = [textfield_ beginningOfDocument];
|
| + UITextPosition* start =
|
| + [textfield_ positionFromPosition:[textfield_ beginningOfDocument]
|
| + offset:i];
|
| +
|
| + // In order to avoid making any assumptions about the length of the text in
|
| + // the field, this test operates by incrementing the |i| and |j| offsets and
|
| + // converting them to opaque UITextPositions. If either |i| or |j| are
|
| + // invalid offsets for the current field text,
|
| + // |positionFromPosition:offset:| is documented to return nil. This is used
|
| + // as a signal to stop incrementing that offset and reset (or end the test).
|
| + while (start) {
|
| + UITextPosition* end =
|
| + [textfield_ positionFromPosition:beginning offset:j];
|
| + while (end) {
|
| + [textfield_
|
| + setSelectedTextRange:[textfield_ textRangeFromPosition:start
|
| + toPosition:end]];
|
| +
|
| + // There are two ways to get the selected text:
|
| + // 1) Ask the field for it directly.
|
| + // 2) Compute the selected NSRange and use that to extract a substring
|
| + // from the field's text.
|
| + // This block of code ensures that the two methods give identical text.
|
| + NSRange nsrange = [textfield_ selectedNSRange];
|
| + NSString* nstext = [[textfield_ text] substringWithRange:nsrange];
|
| + UITextRange* uirange = [textfield_ selectedTextRange];
|
| + NSString* uitext = [textfield_ textInRange:uirange];
|
| + EXPECT_NSEQ(nstext, uitext);
|
| +
|
| + // Increment |j| and |end| for the next iteration of the inner while
|
| + // loop.
|
| + ++j;
|
| + end = [textfield_ positionFromPosition:beginning offset:j];
|
| + }
|
| +
|
| + // Increment |i| and |start| for the next iteration of the outer while
|
| + // loop. This also requires |j| to be reset.
|
| + ++i;
|
| + j = i + 1;
|
| + start = [textfield_ positionFromPosition:beginning offset:i];
|
| + }
|
| +
|
| + [textfield_ resignFirstResponder];
|
| + }
|
| +
|
| + base::scoped_nsobject<OmniboxTextFieldIOS> textfield_;
|
| +};
|
| +
|
| +TEST_F(OmniboxTextFieldIOSTest, BecomeFirstResponderAddsCopyURLMenuItem) {
|
| + // The 'Copy URL' menu item should not be present before this test runs.
|
| + EXPECT_FALSE(IsCopyUrlInMenu());
|
| +
|
| + // Call |becomeFirstResponder| and verify the Copy URL menu item was added.
|
| + UIMenuController* menuController = [UIMenuController sharedMenuController];
|
| + NSUInteger expectedItems = [menuController.menuItems count] + 1;
|
| + [textfield_ becomeFirstResponder];
|
| + EXPECT_EQ(expectedItems, [menuController.menuItems count]);
|
| + EXPECT_TRUE(IsCopyUrlInMenu());
|
| +
|
| + // Call |becomeFirstResponder| again and verify the Copy URL menu item is not
|
| + // added again.
|
| + [textfield_ becomeFirstResponder];
|
| + EXPECT_EQ(expectedItems, [menuController.menuItems count]);
|
| + EXPECT_TRUE(IsCopyUrlInMenu());
|
| +}
|
| +
|
| +TEST_F(OmniboxTextFieldIOSTest, ResignFirstResponderRemovesCopyURLMenuItem) {
|
| + // Call |becomeFirstResponder| to add the 'Copy URL' menu item so this test
|
| + // can remove it.
|
| + [textfield_ becomeFirstResponder];
|
| +
|
| + UIMenuController* menuController = [UIMenuController sharedMenuController];
|
| + NSUInteger expectedItems = [menuController.menuItems count] - 1;
|
| + [textfield_ resignFirstResponder];
|
| + EXPECT_EQ(expectedItems, [menuController.menuItems count]);
|
| + EXPECT_FALSE(IsCopyUrlInMenu());
|
| +}
|
| +
|
| +TEST_F(OmniboxTextFieldIOSTest, enterPreEditState_preEditTextAlignment_short) {
|
| + [textfield_ setText:@"s"];
|
| + [textfield_ becomeFirstResponder];
|
| + [textfield_ enterPreEditState];
|
| + UILabel* preEditLabel = [textfield_ preEditStaticLabel];
|
| + EXPECT_EQ(NSTextAlignmentLeft, preEditLabel.textAlignment);
|
| + [textfield_ resignFirstResponder];
|
| +}
|
| +
|
| +TEST_F(OmniboxTextFieldIOSTest, enterPreEditState_preEditTextAlignment_long) {
|
| + [textfield_ setText:@"some really long text that is wider than the omnibox"];
|
| + [textfield_ becomeFirstResponder];
|
| + [textfield_ enterPreEditState];
|
| + UILabel* preEditLabel = [textfield_ preEditStaticLabel];
|
| + EXPECT_EQ(NSTextAlignmentRight, preEditLabel.textAlignment);
|
| + [textfield_ resignFirstResponder];
|
| +}
|
| +
|
| +TEST_F(OmniboxTextFieldIOSTest, enterPreEditState_preEditTextAlignment_change) {
|
| + [textfield_ setText:@"s"];
|
| + [textfield_ becomeFirstResponder];
|
| + [textfield_ enterPreEditState];
|
| + // Simulate changing the omnibox text while in pre-edit state.
|
| + [textfield_ setText:@"some really long text that is wider than the omnibox"];
|
| + [textfield_ layoutSubviews];
|
| + UILabel* preEditLabel = [textfield_ preEditStaticLabel];
|
| + EXPECT_EQ(NSTextAlignmentLeft, preEditLabel.textAlignment);
|
| + [textfield_ resignFirstResponder];
|
| +}
|
| +
|
| +TEST_F(OmniboxTextFieldIOSTest, rectForDrawTextInRect_entireURLFits) {
|
| + NSString* text = @"http://www.google.com";
|
| + [textfield_ setText:text];
|
| + CGSize textSize = [[textfield_ attributedText] size];
|
| + CGFloat widthForEntireURL = ceil(textSize.width) + 10;
|
| +
|
| + CGRect inputRect = CGRectMake(0, 0, widthForEntireURL, textSize.height);
|
| + CGRect actualRect = [textfield_ rectForDrawTextInRect:inputRect];
|
| + ExpectRectEqual(inputRect, actualRect);
|
| +}
|
| +
|
| +TEST_F(OmniboxTextFieldIOSTest, rectForDrawTextInRect_clippedPrefix) {
|
| + NSString* text = @"http://www.google.com";
|
| + [textfield_ setText:text];
|
| + CGSize textSize = [[textfield_ attributedText] size];
|
| + CGFloat clippedWidth = 10;
|
| + CGFloat widthForPartOfHost = ceil(textSize.width) - clippedWidth;
|
| +
|
| + CGRect inputRect = CGRectMake(0, 0, widthForPartOfHost, textSize.height);
|
| + CGRect actualRect = [textfield_ rectForDrawTextInRect:inputRect];
|
| + CGRect expectedRect =
|
| + CGRectMake(-1 * clippedWidth, 0, ceil(textSize.width), textSize.height);
|
| + ExpectRectEqual(expectedRect, actualRect);
|
| +}
|
| +
|
| +TEST_F(OmniboxTextFieldIOSTest, rectForDrawTextInRect_clippedSuffix) {
|
| + NSString* text = @"http://www.google.com/somelongpath";
|
| + [textfield_ setText:text];
|
| + CGSize textSize = [[textfield_ attributedText] size];
|
| + CGFloat widthForPartOfPath = ceil(textSize.width) - 10;
|
| +
|
| + CGRect inputRect = CGRectMake(0, 0, widthForPartOfPath, textSize.height);
|
| + CGRect actualRect = [textfield_ rectForDrawTextInRect:inputRect];
|
| + CGRect expectedRect = CGRectMake(0, 0, ceil(textSize.width), textSize.height);
|
| + ExpectRectEqual(expectedRect, actualRect);
|
| +}
|
| +
|
| +TEST_F(OmniboxTextFieldIOSTest, rectForDrawTextInRect_noScheme) {
|
| + NSString* text = @"www.google.com";
|
| + [textfield_ setText:text];
|
| + CGSize textSize = [[textfield_ attributedText] size];
|
| +
|
| + CGRect inputRect = CGRectMake(0, 0, ceil(textSize.width), textSize.height);
|
| + CGRect actualRect = [textfield_ rectForDrawTextInRect:inputRect];
|
| + ExpectRectEqual(inputRect, actualRect);
|
| +}
|
| +
|
| +// When the text doesn't contain a host the method bails early and returns
|
| +// the |rect| passed in.
|
| +TEST_F(OmniboxTextFieldIOSTest, rectForDrawTextInRect_noHost) {
|
| + NSString* text = @"http://";
|
| + [textfield_ setText:text];
|
| + CGSize textSize = [[textfield_ attributedText] size];
|
| +
|
| + CGRect inputRect = CGRectMake(0, 0, ceil(textSize.width), textSize.height);
|
| + CGRect actualRect = [textfield_ rectForDrawTextInRect:inputRect];
|
| + ExpectRectEqual(inputRect, actualRect);
|
| +}
|
| +
|
| +TEST_F(OmniboxTextFieldIOSTest, SelectedRanges) {
|
| + base::FilePath test_data_directory;
|
| + ASSERT_TRUE(PathService::Get(ios::DIR_TEST_DATA, &test_data_directory));
|
| + base::FilePath test_file = test_data_directory.Append(
|
| + FILE_PATH_LITERAL("omnibox/selected_ranges.txt"));
|
| + ASSERT_TRUE(base::PathExists(test_file));
|
| +
|
| + std::string contents;
|
| + ASSERT_TRUE(base::ReadFileToString(test_file, &contents));
|
| + std::vector<std::string> test_strings = base::SplitString(
|
| + contents, "\n", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
|
| +
|
| + for (size_t i = 0; i < test_strings.size(); ++i) {
|
| + if (test_strings[i].size() > 0) {
|
| + VerifySelectedNSRanges(base::SysUTF8ToNSString(test_strings[i]));
|
| + }
|
| + }
|
| +}
|
| +
|
| +TEST_F(OmniboxTextFieldIOSTest, SelectExitsPreEditState) {
|
| + [textfield_ enterPreEditState];
|
| + EXPECT_TRUE([textfield_ isPreEditing]);
|
| + [textfield_ select:nil];
|
| + EXPECT_FALSE([textfield_ isPreEditing]);
|
| +}
|
| +
|
| +TEST_F(OmniboxTextFieldIOSTest, SelectAllExitsPreEditState) {
|
| + [textfield_ enterPreEditState];
|
| + EXPECT_TRUE([textfield_ isPreEditing]);
|
| + [textfield_ selectAll:nil];
|
| + EXPECT_FALSE([textfield_ isPreEditing]);
|
| +}
|
| +
|
| +} // namespace
|
|
|