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

Side by Side Diff: ios/chrome/browser/ui/stack_view/card_set_unittest.mm

Issue 2587023002: Upstream Chrome on iOS source code [8/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 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 <QuartzCore/QuartzCore.h>
6
7 #include "base/mac/scoped_nsautorelease_pool.h"
8 #include "base/mac/scoped_nsobject.h"
9 #include "base/strings/stringprintf.h"
10 #import "ios/chrome/browser/tabs/tab.h"
11 #import "ios/chrome/browser/tabs/tab_model.h"
12 #import "ios/chrome/browser/tabs/tab_model_observer.h"
13 #include "ios/chrome/browser/ui/rtl_geometry.h"
14 #import "ios/chrome/browser/ui/stack_view/card_set.h"
15 #import "ios/chrome/browser/ui/stack_view/card_stack_layout_manager.h"
16 #import "ios/chrome/browser/ui/stack_view/stack_card.h"
17 #import "ios/testing/ocmock_complex_type_helper.h"
18 #include "testing/gtest/include/gtest/gtest.h"
19 #include "testing/gtest_mac.h"
20 #include "testing/platform_test.h"
21 #import "third_party/ocmock/OCMock/OCMock.h"
22 #import "third_party/ocmock/gtest_support.h"
23
24 @interface MockTabModel : NSObject<NSFastEnumeration> {
25 @private
26 base::scoped_nsobject<NSMutableArray> tabs_;
27 id<TabModelObserver> observer_; // weak
28 }
29
30 // Adds a new mock tab with the given properties.
31 - (void)addTabWithTitle:(NSString*)title location:(const GURL&)url;
32
33 // TabModel mocking.
34 - (NSUInteger)count;
35 - (BOOL)isOffTheRecord;
36 - (Tab*)currentTab;
37 - (NSUInteger)indexOfTab:(Tab*)tab;
38 - (Tab*)tabAtIndex:(NSUInteger)tabIndex;
39 - (void)addObserver:(id<TabModelObserver>)observer;
40 - (void)removeObserver:(id<TabModelObserver>)observer;
41 - (id<TabModelObserver>)observer;
42 @end
43
44 @interface CardSetTestTabMock : OCMockComplexTypeHelper
45 @end
46 @implementation CardSetTestTabMock
47
48 typedef const GURL& (^CardSetTestTabMock_url)(void);
49
50 - (const GURL&)url {
51 return static_cast<CardSetTestTabMock_url>([self blockForSelector:_cmd])();
52 }
53 @end
54
55 @implementation MockTabModel
56
57 - (id)init {
58 if ((self = [super init])) {
59 tabs_.reset([[NSMutableArray alloc] init]);
60 }
61 return self;
62 }
63
64 - (void)addTabWithTitle:(NSString*)title location:(const GURL&)url {
65 base::scoped_nsobject<id> tab([[CardSetTestTabMock alloc]
66 initWithRepresentedObject:[OCMockObject mockForClass:[Tab class]]]);
67 UIView* dummyView = [[[UIView alloc] initWithFrame:CGRectZero] autorelease];
68 static int sCounter = 0;
69 NSString* sessionID = [NSString stringWithFormat:@"%d", sCounter++];
70 BOOL no = NO;
71 [[[tab stub] andReturn:dummyView] view];
72 base::scoped_nsobject<id> block([^{
73 return (const GURL&)url;
74 } copy]);
75 [tab onSelector:@selector(url) callBlockExpectation:block];
76
77 [[tab expect] retrieveSnapshot:[OCMArg any]];
78 [[[tab stub] andReturn:nil] webController];
79 [[[tab stub] andReturn:nil] favicon];
80 [[[tab stub] andReturnValue:OCMOCK_VALUE(no)] canGoBack];
81 [[[tab stub] andReturnValue:OCMOCK_VALUE(no)] canGoForward];
82 [[[tab stub] andReturn:title] title];
83 [[[tab stub] andReturn:sessionID] currentSessionID];
84
85 [tabs_ addObject:tab];
86 [observer_ tabModel:(TabModel*)self
87 didInsertTab:tab
88 atIndex:([tabs_ count] - 1)
89 inForeground:YES];
90 }
91
92 - (void)removeTabAtIndex:(NSUInteger)index {
93 id tab = [tabs_ objectAtIndex:index];
94 [[tab retain] autorelease];
95 [tabs_ removeObjectAtIndex:index];
96
97 // A tab was removed at the given index.
98 [observer_ tabModel:(TabModel*)self didRemoveTab:tab atIndex:index];
99 }
100
101 - (NSUInteger)count {
102 return [tabs_ count];
103 }
104
105 - (BOOL)isOffTheRecord {
106 return NO;
107 }
108
109 - (Tab*)currentTab {
110 if ([tabs_ count])
111 return [tabs_ objectAtIndex:0];
112 return nil;
113 }
114
115 - (NSUInteger)indexOfTab:(Tab*)tab {
116 return [tabs_ indexOfObject:tab];
117 }
118
119 - (Tab*)tabAtIndex:(NSUInteger)tabIndex {
120 return [tabs_ objectAtIndex:tabIndex];
121 }
122
123 - (void)addObserver:(id<TabModelObserver>)observer {
124 observer_ = observer;
125 }
126
127 - (void)removeObserver:(id<TabModelObserver>)observer {
128 observer_ = nil;
129 }
130
131 - (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState*)state
132 objects:(id*)stackbuf
133 count:(NSUInteger)len {
134 return [tabs_ countByEnumeratingWithState:state objects:stackbuf count:len];
135 }
136
137 - (id<TabModelObserver>)observer {
138 return observer_;
139 }
140
141 @end
142
143 #pragma mark -
144
145 namespace {
146
147 const CGFloat kViewportDimension = 100;
148 const CGFloat kCardDimension = 90;
149
150 CardStackLayoutManager* CreateMockCardStackLayoutManager() {
151 OCMockObject* stackModelMock =
152 [OCMockObject mockForClass:[CardStackLayoutManager class]];
153 BOOL no = NO;
154 [[[stackModelMock stub] andReturnValue:OCMOCK_VALUE(no)] layoutIsVertical];
155 NSUInteger lastStartStackCardIndex = 0;
156 [[[stackModelMock stub] andReturnValue:OCMOCK_VALUE(lastStartStackCardIndex)]
157 lastStartStackCardIndex];
158 NSArray* cards = @[];
159 [[[stackModelMock stub] andReturn:cards] cards];
160 return (CardStackLayoutManager*)stackModelMock;
161 }
162
163 class CardSetTest : public PlatformTest {
164 protected:
165 virtual void SetUpWithTabs(int nb_tabs) {
166 tab_model_.reset([[MockTabModel alloc] init]);
167
168 for (int i = 0; i < nb_tabs; ++i) {
169 std::string url = base::StringPrintf("http://%d.example.com", i);
170 [tab_model_ addTabWithTitle:@"NewTab" location:GURL(url)];
171 }
172
173 card_set_.reset(
174 [[CardSet alloc] initWithModel:(TabModel*)tab_model_.get()]);
175
176 display_view_.reset(
177 [[UIView alloc] initWithFrame:CGRectMake(0, 0, kViewportDimension,
178 kViewportDimension)]);
179 // Do some initial configuration of the card set.
180 [card_set_ setDisplayView:display_view_];
181 [card_set_ setCardSize:CGSizeMake(kCardDimension, kCardDimension)];
182 [card_set_ setLayoutAxisPosition:(kViewportDimension / 2.0) isVertical:YES];
183 [card_set_ configureLayoutParametersWithMargin:10];
184 }
185
186 void SetUp() override { SetUpWithTabs(2); }
187
188 base::scoped_nsobject<MockTabModel> tab_model_;
189 base::scoped_nsobject<UIView> display_view_;
190 base::scoped_nsobject<CardSet> card_set_;
191 };
192
193 TEST_F(CardSetTest, InitialLayoutState) {
194 NSArray* cards = [card_set_ cards];
195 EXPECT_EQ([tab_model_ count], [cards count]);
196
197 // Tabs should be on the trailing side.
198 EXPECT_EQ(CardCloseButtonSide::TRAILING, [card_set_ closeButtonSide]);
199
200 // At least one card should be visible after layout, and cards should have
201 // the right size and center.
202 [card_set_ fanOutCards];
203 BOOL has_visible_card = NO;
204 for (StackCard* card in cards) {
205 if ([card viewIsLive])
206 has_visible_card = YES;
207 EXPECT_FLOAT_EQ(kCardDimension, card.layout.size.width);
208 EXPECT_FLOAT_EQ(kCardDimension, card.layout.size.height);
209 EXPECT_FLOAT_EQ(kViewportDimension / 2.0,
210 CGRectGetMidX(LayoutRectGetRect(card.layout)));
211 }
212 EXPECT_TRUE(has_visible_card);
213 }
214
215 TEST_F(CardSetTest, HandleRotation) {
216 // Rotate the card set.
217 [card_set_ setLayoutAxisPosition:(kViewportDimension / 3.0) isVertical:NO];
218
219 // Tabs should now be on the leading side.
220 EXPECT_EQ(CardCloseButtonSide::LEADING, [card_set_ closeButtonSide]);
221 // And the centers should be on the new axis.
222 for (StackCard* card in [card_set_ cards]) {
223 EXPECT_FLOAT_EQ(kViewportDimension / 3.0,
224 CGRectGetMidY(LayoutRectGetRect(card.layout)));
225 }
226 }
227
228 TEST_F(CardSetTest, CurrentCard) {
229 NSUInteger current_tab_index =
230 [tab_model_ indexOfTab:[tab_model_ currentTab]];
231 NSArray* cards = [card_set_ cards];
232 NSUInteger current_card_index = [cards indexOfObject:[card_set_ currentCard]];
233 EXPECT_EQ(current_tab_index, current_card_index);
234 }
235
236 TEST_F(CardSetTest, ViewClearing) {
237 // Add the views.
238 [card_set_ fanOutCards];
239 ASSERT_GT([[display_view_ subviews] count], 0U);
240 [card_set_ setDisplayView:nil];
241 EXPECT_EQ(0U, [[display_view_ subviews] count]);
242 }
243
244 TEST_F(CardSetTest, NoticeTabAddition) {
245 NSArray* cards = [card_set_ cards];
246 NSUInteger initial_card_count = [cards count];
247
248 OCMockObject* observer =
249 [OCMockObject mockForProtocol:@protocol(CardSetObserver)];
250 [[observer expect] cardSet:OCMOCK_ANY didAddCard:OCMOCK_ANY];
251 [card_set_ setObserver:(id<CardSetObserver>)observer];
252
253 [tab_model_ addTabWithTitle:@"NewTab"
254 location:GURL("http://www.example.com")];
255 cards = [card_set_ cards];
256 EXPECT_EQ(initial_card_count + 1, [cards count]);
257
258 [card_set_ setObserver:nil];
259 EXPECT_OCMOCK_VERIFY(observer);
260 }
261
262 TEST_F(CardSetTest, NoticeTabRemoval) {
263 NSArray* cards = [card_set_ cards];
264 NSUInteger initial_card_count = [cards count];
265 StackCard* first_card = [cards objectAtIndex:0];
266
267 OCMockObject* observer =
268 [OCMockObject mockForProtocol:@protocol(CardSetObserver)];
269 [[observer expect] cardSet:OCMOCK_ANY willRemoveCard:OCMOCK_ANY atIndex:0];
270 [[observer expect] cardSet:OCMOCK_ANY didRemoveCard:OCMOCK_ANY atIndex:0];
271
272 [card_set_ setObserver:(id<CardSetObserver>)observer];
273
274 [tab_model_ removeTabAtIndex:0];
275 cards = [card_set_ cards];
276 EXPECT_EQ(initial_card_count - 1, [cards count]);
277 EXPECT_NE(first_card, [cards objectAtIndex:0]);
278
279 [card_set_ setObserver:nil];
280 EXPECT_OCMOCK_VERIFY(observer);
281 }
282
283 TEST_F(CardSetTest, Preloading) {
284 // Preloading when everything is visible should return NO.
285 [card_set_ fanOutCards];
286 EXPECT_FALSE([card_set_ preloadNextCard]);
287
288 // Add a bunch of cards to ensure stacking.
289 for (int i = 0; i < 20; ++i) {
290 [tab_model_ addTabWithTitle:@"NewTab"
291 location:GURL("http://www.example.com")];
292 }
293 [card_set_ fanOutCards];
294
295 NSUInteger loaded_cards = [[display_view_ subviews] count];
296 // Now preloading should return YES, and should have added one more card to
297 // the view.
298 EXPECT_TRUE([card_set_ preloadNextCard]);
299 EXPECT_EQ(loaded_cards + 1, [[display_view_ subviews] count]);
300 }
301
302 TEST_F(CardSetTest, stackIsFullyCollapsed) {
303 [card_set_ setStackModelForTesting:CreateMockCardStackLayoutManager()];
304 OCMockObject* stack_model_mock = (OCMockObject*)[card_set_ stackModel];
305 [[stack_model_mock expect] stackIsFullyCollapsed];
306 [card_set_ stackIsFullyCollapsed];
307 EXPECT_OCMOCK_VERIFY(stack_model_mock);
308 }
309
310 TEST_F(CardSetTest, stackIsFullyFannedOut) {
311 [card_set_ setStackModelForTesting:CreateMockCardStackLayoutManager()];
312 OCMockObject* stack_model_mock = (OCMockObject*)[card_set_ stackModel];
313 [[stack_model_mock expect] stackIsFullyFannedOut];
314 [card_set_ stackIsFullyFannedOut];
315 EXPECT_OCMOCK_VERIFY(stack_model_mock);
316 }
317
318 TEST_F(CardSetTest, stackIsFullyOverextended) {
319 [card_set_ setStackModelForTesting:CreateMockCardStackLayoutManager()];
320 OCMockObject* stack_model_mock = (OCMockObject*)[card_set_ stackModel];
321 [[stack_model_mock expect] stackIsFullyOverextended];
322 [card_set_ stackIsFullyOverextended];
323 EXPECT_OCMOCK_VERIFY(stack_model_mock);
324 }
325
326 TEST_F(CardSetTest, isCardInStartStaggerRegion) {
327 [card_set_ fanOutCards];
328 NSArray* cards = [card_set_ cards];
329 // First card should not be collapsed into start stagger region when stack is
330 // fanned out from the first card.
331 StackCard* first_card = [cards objectAtIndex:0];
332 EXPECT_FALSE([card_set_ isCardInStartStaggerRegion:first_card]);
333 // Add a bunch of cards to ensure stacking, and fan them out so that there
334 // is a start stack.
335 for (int i = 0; i < 20; ++i) {
336 [tab_model_ addTabWithTitle:@"NewTab"
337 location:GURL("http://www.example.com")];
338 }
339 [card_set_ fanOutCardsWithStartIndex:10];
340 // First card should now be collapsed into start stagger region.
341 EXPECT_TRUE([card_set_ isCardInStartStaggerRegion:first_card]);
342 }
343
344 TEST_F(CardSetTest, isCardInEndStaggerRegion) {
345 [card_set_ fanOutCards];
346 NSArray* cards = [card_set_ cards];
347 // Add a bunch of cards to ensure stacking, and fan them out so that there
348 // is an end stack.
349 for (int i = 0; i < 20; ++i) {
350 [tab_model_ addTabWithTitle:@"NewTab"
351 location:GURL("http://www.example.com")];
352 }
353 StackCard* last_card = [cards objectAtIndex:[cards count] - 1];
354 [card_set_ fanOutCards];
355 // Last card should be collapsed into end region.
356 EXPECT_TRUE([card_set_ isCardInEndStaggerRegion:last_card]);
357
358 // Fan out cards from the last card.
359 [card_set_ fanOutCardsWithStartIndex:[cards count] - 1];
360 // Last card should not be collapsed into end region.
361 EXPECT_FALSE([card_set_ isCardInEndStaggerRegion:last_card]);
362 }
363
364 TEST_F(CardSetTest, setTabModel) {
365 SetUpWithTabs(0);
366 [card_set_ setTabModel:nil];
367 EXPECT_TRUE([tab_model_ observer] == nil);
368 [card_set_ setTabModel:static_cast<id>(tab_model_)];
369 EXPECT_NSEQ(card_set_, static_cast<id>([tab_model_ observer]));
370 }
371
372 } // namespace
OLDNEW
« no previous file with comments | « ios/chrome/browser/ui/stack_view/card_set.mm ('k') | ios/chrome/browser/ui/stack_view/card_stack_layout_manager.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698