Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(194)

Side by Side Diff: ios/chrome/browser/ui/omnibox_perftest.mm

Issue 2589803002: Upstream Chrome on iOS source code [6/11]. (Closed)
Patch Set: Created 4 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #import <UIKit/UIKit.h>
6
7 #include <memory>
8
9 #include "base/mac/scoped_nsobject.h"
10 #import "base/test/ios/wait_util.h"
11 #include "base/time/time.h"
12 #include "components/toolbar/test_toolbar_model.h"
13 #include "ios/chrome/browser/autocomplete/autocomplete_classifier_factory.h"
14 #include "ios/chrome/browser/browser_state/test_chrome_browser_state.h"
15 #include "ios/chrome/browser/search_engines/template_url_service_factory.h"
16 #import "ios/chrome/browser/tabs/tab.h"
17 #import "ios/chrome/browser/tabs/tab_model.h"
18 #include "ios/chrome/browser/ui/omnibox/location_bar_view_ios.h"
19 #import "ios/chrome/browser/ui/omnibox/omnibox_text_field_ios.h"
20 #include "ios/chrome/browser/ui/toolbar/toolbar_model_delegate_ios.h"
21 #include "ios/chrome/browser/ui/toolbar/toolbar_model_impl_ios.h"
22 #import "ios/chrome/browser/ui/toolbar/web_toolbar_controller.h"
23 #include "ios/chrome/test/base/perf_test_ios.h"
24 #include "testing/platform_test.h"
25 #import "third_party/ocmock/OCMock/OCMock.h"
26 #import "ui/base/test/ios/keyboard_appearance_listener.h"
27
28 namespace {
29
30 // Descends down a view hierarchy until the first view of |specificClass|
31 // is found. Returns nil if a view of |specificClass| cannot be found.
32 UIView* FindViewByClass(UIView* topView, Class specificClass) {
33 if ([topView isKindOfClass:specificClass])
34 return [topView window] ? topView : nil;
35 for (UIView* subview in [topView subviews]) {
36 UIView* foundView = FindViewByClass(subview, specificClass);
37 if (foundView)
38 return foundView;
39 }
40 return nil;
41 }
42
43 // Constant for UI wait loop.
44 const NSTimeInterval kSpinDelaySeconds = 0.01;
45
46 class OmniboxPerfTest : public PerfTest {
47 public:
48 OmniboxPerfTest() : PerfTest("Omnibox") {}
49
50 protected:
51 void SetUp() override {
52 PerfTest::SetUp();
53 TestChromeBrowserState::Builder test_cbs_builder;
54 test_cbs_builder.AddTestingFactory(
55 ios::TemplateURLServiceFactory::GetInstance(),
56 ios::TemplateURLServiceFactory::GetDefaultFactory());
57 test_cbs_builder.AddTestingFactory(
58 ios::AutocompleteClassifierFactory::GetInstance(),
59 ios::AutocompleteClassifierFactory::GetDefaultFactory());
60 chrome_browser_state_ = test_cbs_builder.Build();
61
62 // Prepares testing profile for autocompletion.
63 ios::AutocompleteClassifierFactory::GetForBrowserState(
64 chrome_browser_state_.get());
65
66 // Sets up the listener for keyboard activation/deactivation notifications.
67 keyboard_listener_.reset([[KeyboardAppearanceListener alloc] init]);
68
69 // Create a real window to host the Toolbar.
70 CGRect screenBounds = [[UIScreen mainScreen] bounds];
71 window_.reset([[UIWindow alloc] initWithFrame:screenBounds]);
72 [window_ makeKeyAndVisible];
73
74 // Create a mock Tab and a TabModel that will always return the mock Tab as
75 // the current tab.
76 current_tab_.reset(
77 [(Tab*)[OCMockObject niceMockForClass:[Tab class]] retain]);
78 id tab_model = [OCMockObject mockForClass:[TabModel class]];
79 [[[tab_model stub] andReturn:current_tab_] currentTab];
80 tab_model_.reset([tab_model retain]);
81
82 // Creates the Toolbar for testing and sizes it to the width of the screen.
83 toolbar_model_delegate_.reset(
84 new ToolbarModelDelegateIOS(tab_model_.get()));
85 toolbar_model_ios_.reset(
86 new ToolbarModelImplIOS(toolbar_model_delegate_.get()));
87
88 // The OCMOCK_VALUE macro doesn't like std::unique_ptr, but it works just
89 // fine if a temporary variable is used.
90 ToolbarModelIOS* model_for_mock = toolbar_model_ios_.get();
91 id webToolbarDelegate =
92 [OCMockObject niceMockForProtocol:@protocol(WebToolbarDelegate)];
93 [[[webToolbarDelegate stub] andReturnValue:OCMOCK_VALUE(model_for_mock)]
94 toolbarModelIOS];
95 id urlLoader = [OCMockObject niceMockForProtocol:@protocol(UrlLoader)];
96 toolbar_.reset([[WebToolbarController alloc]
97 initWithDelegate:webToolbarDelegate
98 urlLoader:urlLoader
99 browserState:chrome_browser_state_.get()
100 preloadProvider:nil]);
101 UIView* toolbarView = [toolbar_ view];
102 CGRect toolbarFrame = toolbarView.frame;
103 toolbarFrame.origin = CGPointZero;
104 toolbarFrame.size.width = screenBounds.size.width;
105 toolbarView.frame = toolbarFrame;
106 // Add toolbar to window.
107 [window_ addSubview:toolbarView];
108 base::test::ios::WaitUntilCondition(^bool() {
109 return IsToolbarLoaded(window_.get());
110 });
111 }
112
113 void TearDown() override {
114 // Remove toolbar from window.
115 [[toolbar_ view] removeFromSuperview];
116 base::test::ios::WaitUntilCondition(^bool() {
117 return !IsToolbarLoaded(window_.get());
118 });
119 [toolbar_ browserStateDestroyed];
120 PerfTest::TearDown();
121 }
122
123 // Returns whether Omnibox has been loaded.
124 bool IsToolbarLoaded(UIView* topView) {
125 return FindViewByClass(topView, [OmniboxTextFieldIOS class]) != nil;
126 }
127
128 // Inserts the |text| string into the |textField| and return the amount
129 // of time it took to complete the insertion. This does not time
130 // any activities that may be triggered on other threads.
131 base::TimeDelta TimeInsertText(OmniboxTextFieldIOS* textField,
132 NSString* text) {
133 base::Time startTime = base::Time::NowFromSystemTime();
134 [textField insertTextWhileEditing:text];
135 base::TimeDelta elapsed = base::Time::NowFromSystemTime() - startTime;
136 // Adds a small delay so the run loop can update the screen.
137 // The user experience measurement should include this visual
138 // feedback to the user, but there is no way of catching when
139 // the typed character showed up in the omnibox on screen.
140 base::test::ios::SpinRunLoopWithMaxDelay(
141 base::TimeDelta::FromSecondsD(kSpinDelaySeconds));
142 return elapsed;
143 }
144
145 // Creates a dummy text field and make it be a first responder so keyboard
146 // comes up. In general, there's a lot of time spent in loading up various
147 // graphics assets on a keyboard which may distort the measurement of Chrome
148 // Omnibox focus timings. Call this function to preload keyboard before
149 // doing the real test.
150 base::TimeDelta PreLoadKeyboard() {
151 base::scoped_nsobject<UITextField> textField(
152 [[UITextField alloc] initWithFrame:CGRectMake(20, 100, 280, 29)]);
153 [textField setBorderStyle:UITextBorderStyleRoundedRect];
154 [window_ addSubview:textField];
155 base::TimeDelta elapsed = base::test::ios::TimeUntilCondition(
156 ^{
157 [textField becomeFirstResponder];
158 },
159 ^bool() {
160 return [keyboard_listener_ isKeyboardVisible];
161 },
162 nullptr, base::TimeDelta());
163 base::test::ios::TimeUntilCondition(
164 ^{
165 [textField resignFirstResponder];
166 },
167 ^bool() {
168 return ![keyboard_listener_ isKeyboardVisible];
169 },
170 nullptr, base::TimeDelta());
171 [textField removeFromSuperview];
172 return elapsed;
173 }
174
175 // Enables the on-screen keyboard as if user has tapped on |textField|.
176 // Returns the amount of time it took for the keyboard to appear.
177 base::TimeDelta EnableKeyboard(OmniboxTextFieldIOS* textField) {
178 return base::test::ios::TimeUntilCondition(
179 ^{
180 [textField becomeFirstResponder];
181 },
182 ^bool() {
183 return [keyboard_listener_ isKeyboardVisible];
184 },
185 nullptr, base::TimeDelta());
186 }
187
188 // Performs necessary cleanup (so next pass of unit test can start from
189 // a clean slate) and then exit from |textField| to dismiss keyboard.
190 void DisableKeyboard(OmniboxTextFieldIOS* textField) {
191 // Busy wait until keyboard is hidden.
192 base::test::ios::TimeUntilCondition(
193 ^{
194 [textField exitPreEditState];
195 [textField resignFirstResponder];
196 },
197 ^bool() {
198 return ![keyboard_listener_ isKeyboardVisible];
199 },
200 nullptr, base::TimeDelta());
201 }
202
203 std::unique_ptr<TestChromeBrowserState> chrome_browser_state_;
204 base::scoped_nsobject<Tab> current_tab_;
205 base::scoped_nsobject<TabModel> tab_model_;
206 std::unique_ptr<ToolbarModelDelegateIOS> toolbar_model_delegate_;
207 std::unique_ptr<ToolbarModelIOS> toolbar_model_ios_;
208 base::scoped_nsobject<WebToolbarController> toolbar_;
209 base::scoped_nsobject<UIWindow> window_;
210 base::scoped_nsobject<KeyboardAppearanceListener> keyboard_listener_;
211 };
212
213 // Measures the amount of time it takes the Omnibox text field to activate
214 // the on-screen keyboard.
215 TEST_F(OmniboxPerfTest, TestTextFieldDidBeginEditing) {
216 LogPerfTiming("Keyboard preload", PreLoadKeyboard());
217 OmniboxTextFieldIOS* textField = (OmniboxTextFieldIOS*)FindViewByClass(
218 [toolbar_ view], [OmniboxTextFieldIOS class]);
219
220 // Time how long it takes to "focus" on omnibox.
221 RepeatTimedRuns("Begin editing",
222 ^base::TimeDelta(int index) {
223 return EnableKeyboard(textField);
224 },
225 ^() {
226 DisableKeyboard(textField);
227 });
228 }
229
230 // Measures the amount of time it takes to type in the first character
231 // into the Omnibox.
232 TEST_F(OmniboxPerfTest, TestTypeOneCharInTextField) {
233 OmniboxTextFieldIOS* textField = (OmniboxTextFieldIOS*)FindViewByClass(
234 [toolbar_ view], [OmniboxTextFieldIOS class]);
235 RepeatTimedRuns("Type first character",
236 ^base::TimeDelta(int index) {
237 EnableKeyboard(textField);
238 return TimeInsertText(textField, @"G");
239 },
240 ^() {
241 [textField setText:@""];
242 DisableKeyboard(textField);
243 });
244 }
245
246 // Measures the amount of time it takes to type in the word "google" one
247 // letter at a time.
248 TEST_F(OmniboxPerfTest, TestTypingInTextField) {
249 OmniboxTextFieldIOS* textField = (OmniboxTextFieldIOS*)FindViewByClass(
250 [toolbar_ view], [OmniboxTextFieldIOS class]);
251 // The characters to type into the omnibox text field.
252 NSArray* inputCharacters =
253 [NSArray arrayWithObjects:@"g", @"o", @"o", @"g", @"l", @"e", nil];
254 RepeatTimedRuns(
255 "Typing",
256 ^base::TimeDelta(int index) {
257 EnableKeyboard(textField);
258 NSMutableString* logMessage = [NSMutableString string];
259 base::TimeDelta elapsed;
260 for (NSString* input in inputCharacters) {
261 base::TimeDelta inputElapsed = TimeInsertText(textField, input);
262 [logMessage appendFormat:@"%@'%@':%.0f",
263 [logMessage length] ? @" " : @"", input,
264 inputElapsed.InMillisecondsF()];
265 elapsed += inputElapsed;
266 }
267 NSLog(@"%2d: %@", index, logMessage);
268 return elapsed;
269 },
270 ^() {
271 [textField setText:@""];
272 DisableKeyboard(textField);
273 });
274 }
275 }
OLDNEW
« no previous file with comments | « ios/chrome/browser/ui/omnibox/truncating_attributed_label.mm ('k') | ios/chrome/browser/ui/open_in_controller.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698