OLD | NEW |
(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/logging.h" |
| 8 #include "base/mac/scoped_nsautorelease_pool.h" |
| 9 #include "base/mac/scoped_nsobject.h" |
| 10 #import "ios/chrome/browser/tabs/tab_model.h" |
| 11 #import "ios/chrome/browser/ui/stack_view/card_set.h" |
| 12 #import "ios/chrome/browser/ui/stack_view/stack_card.h" |
| 13 #import "ios/chrome/browser/ui/stack_view/stack_view_controller.h" |
| 14 #import "ios/chrome/browser/ui/stack_view/stack_view_controller_private.h" |
| 15 #include "ios/chrome/test/block_cleanup_test.h" |
| 16 #include "testing/gtest/include/gtest/gtest.h" |
| 17 #include "testing/gtest_mac.h" |
| 18 #include "third_party/ocmock/OCMock/OCMock.h" |
| 19 |
| 20 namespace { |
| 21 |
| 22 const CGFloat kViewportDimension = 200; |
| 23 |
| 24 } // namespace |
| 25 |
| 26 #pragma mark - |
| 27 |
| 28 @interface MockCardSet : NSObject { |
| 29 @private |
| 30 UIView* displayView_; |
| 31 CGSize cardSize_; |
| 32 CGFloat layoutAxisPosition_; |
| 33 BOOL initialConfigurationSet_; |
| 34 id observer_; |
| 35 } |
| 36 |
| 37 // CardSet simulation |
| 38 @property(nonatomic, retain, readwrite) UIView* displayView; |
| 39 @property(nonatomic, assign, readwrite) CGSize cardSize; |
| 40 @property(nonatomic, assign, readwrite) id<CardSetObserver> observer; |
| 41 @property(nonatomic, assign, readwrite) BOOL keepOnlyVisibleCardViewsAlive; |
| 42 |
| 43 - (void)configureLayoutParametersWithMargin:(CGFloat)margin; |
| 44 - (void)setLayoutAxisPosition:(CGFloat)position |
| 45 isVertical:(BOOL)layoutIsVertical; |
| 46 - (void)clearGestureRecognizerTargetAndDelegateFromCards:(id)object; |
| 47 - (NSArray*)cards; |
| 48 - (CGFloat)maximumStackLength; |
| 49 - (void)displayViewSizeWasChanged; |
| 50 - (TabModel*)tabModel; |
| 51 - (void)setTabModel:(TabModel*)tabModel; |
| 52 |
| 53 // Testing helpers |
| 54 - (BOOL)configured; |
| 55 @property(nonatomic, assign, readonly) CGFloat layoutAxisPosition; |
| 56 @end |
| 57 |
| 58 @implementation MockCardSet |
| 59 |
| 60 @synthesize displayView = displayView_; |
| 61 @synthesize cardSize = cardSize_; |
| 62 @synthesize observer = observer_; |
| 63 @synthesize layoutAxisPosition = layoutAxisPosition_; |
| 64 @synthesize keepOnlyVisibleCardViewsAlive = keepOnlyVisibleCardViewsAlive_; |
| 65 |
| 66 - (BOOL)configured { |
| 67 return initialConfigurationSet_ && (layoutAxisPosition_ != 0); |
| 68 } |
| 69 |
| 70 - (void)configureLayoutParametersWithMargin:(CGFloat)margin { |
| 71 initialConfigurationSet_ = YES; |
| 72 } |
| 73 |
| 74 - (void)setLayoutAxisPosition:(CGFloat)position |
| 75 isVertical:(BOOL)layoutIsVertical { |
| 76 layoutAxisPosition_ = position; |
| 77 } |
| 78 |
| 79 - (void)clearGestureRecognizerTargetAndDelegateFromCards:(id)object { |
| 80 } |
| 81 |
| 82 - (NSArray*)cards { |
| 83 // TODO(stuartmorgan): Return an actual set of cards to allow for more |
| 84 // interesting tests. For now this is just to satisfy the toolbar updating |
| 85 // code that shows the card count. |
| 86 return [NSArray array]; |
| 87 } |
| 88 |
| 89 - (CGFloat)maximumStackLength { |
| 90 return 2.0 * kViewportDimension; |
| 91 } |
| 92 |
| 93 - (void)displayViewSizeWasChanged { |
| 94 } |
| 95 |
| 96 - (TabModel*)tabModel { |
| 97 return nil; |
| 98 } |
| 99 |
| 100 - (void)setTabModel:(TabModel*)tabModel { |
| 101 } |
| 102 |
| 103 @end |
| 104 |
| 105 #pragma mark - |
| 106 |
| 107 namespace { |
| 108 |
| 109 class StackViewControllerTest : public BlockCleanupTest { |
| 110 protected: |
| 111 void SetUp() override { |
| 112 BlockCleanupTest::SetUp(); |
| 113 |
| 114 main_card_set_.reset([[MockCardSet alloc] init]); |
| 115 otr_card_set_.reset([[MockCardSet alloc] init]); |
| 116 |
| 117 view_controller_.reset([[StackViewController alloc] |
| 118 initWithMainCardSet:(CardSet*)main_card_set_.get() |
| 119 otrCardSet:(CardSet*)otr_card_set_.get() |
| 120 activeCardSet:(CardSet*)main_card_set_.get()]); |
| 121 // Resize the view and call VC lifecycle events |
| 122 [view_controller_ view].frame = |
| 123 CGRectMake(0.0, 0.0, kViewportDimension, kViewportDimension); |
| 124 // Simulate displaying the view. |
| 125 [view_controller_ viewWillAppear:NO]; |
| 126 } |
| 127 void TearDown() override { |
| 128 // The view controller uses a delayed selector call, so in the unittests |
| 129 // that causes the controller to be retained and outlive the test. |
| 130 [NSObject cancelPreviousPerformRequestsWithTarget:view_controller_.get()]; |
| 131 // And there are likely animations still running. |
| 132 for (UIView* view in [[view_controller_ scrollView] subviews]) { |
| 133 // Remove any animations on cards themselves. |
| 134 for (UIView* subview in [view subviews]) { |
| 135 [subview.layer removeAllAnimations]; |
| 136 } |
| 137 [view.layer removeAllAnimations]; |
| 138 } |
| 139 [[[view_controller_ scrollView] layer] removeAllAnimations]; |
| 140 |
| 141 // Manually run teardown. |
| 142 [view_controller_ cleanUpViewsAndNotifications]; |
| 143 |
| 144 BlockCleanupTest::TearDown(); |
| 145 } |
| 146 |
| 147 // Checks that the display view of |card_set| is correctly set up: |
| 148 // - sized to match the size of the scroll view. |
| 149 // - origin set to 0 on the non-layout axis, and to the scroll view's content |
| 150 // offset on the layout axis. |
| 151 // Also checks that the content size of the scroll view is configured |
| 152 // appropriately for this card set: |
| 153 // - greater than the maximum stack size along the layout axis to give enough |
| 154 // space to fully scroll the cards to beginning/end without hitting the |
| 155 // scroll view's boundaries. |
| 156 // - equal to the display view size along the non-layout axis. |
| 157 void ValidateDisplaySetupForCardSet(MockCardSet* card_set) { |
| 158 DCHECK(card_set == main_card_set_ || card_set == otr_card_set_); |
| 159 EXPECT_FLOAT_EQ([[card_set displayView] bounds].size.width, |
| 160 [[view_controller_ scrollView] bounds].size.width); |
| 161 EXPECT_FLOAT_EQ([[card_set displayView] bounds].size.height, |
| 162 [[view_controller_ scrollView] bounds].size.height); |
| 163 CGPoint display_view_origin = [[card_set displayView] frame].origin; |
| 164 BOOL is_portrait = UIInterfaceOrientationIsPortrait( |
| 165 [UIApplication sharedApplication].statusBarOrientation); |
| 166 CGFloat content_offset = |
| 167 is_portrait ? [[view_controller_ scrollView] contentOffset].y |
| 168 : [[view_controller_ scrollView] contentOffset].x; |
| 169 if (is_portrait) { |
| 170 EXPECT_FLOAT_EQ(display_view_origin.x, 0); |
| 171 EXPECT_FLOAT_EQ(display_view_origin.y, content_offset); |
| 172 EXPECT_GT([[view_controller_ scrollView] contentSize].height, |
| 173 [card_set maximumStackLength]); |
| 174 EXPECT_FLOAT_EQ(card_set.displayView.bounds.size.width, |
| 175 [[view_controller_ scrollView] contentSize].width); |
| 176 } else { |
| 177 EXPECT_FLOAT_EQ(display_view_origin.x, content_offset); |
| 178 EXPECT_FLOAT_EQ(display_view_origin.y, 0); |
| 179 EXPECT_GT([[view_controller_ scrollView] contentSize].width, |
| 180 [card_set maximumStackLength]); |
| 181 EXPECT_FLOAT_EQ(card_set.displayView.bounds.size.height, |
| 182 [[view_controller_ scrollView] contentSize].height); |
| 183 } |
| 184 } |
| 185 |
| 186 base::scoped_nsobject<StackViewController> view_controller_; |
| 187 base::scoped_nsobject<MockCardSet> main_card_set_; |
| 188 base::scoped_nsobject<MockCardSet> otr_card_set_; |
| 189 }; |
| 190 |
| 191 TEST_F(StackViewControllerTest, BasicConfiguration) { |
| 192 // Ensure that the CardSet is configured and correctly laid out. |
| 193 EXPECT_TRUE([main_card_set_ configured]); |
| 194 EXPECT_TRUE([otr_card_set_ configured]); |
| 195 ValidateDisplaySetupForCardSet(main_card_set_); |
| 196 ValidateDisplaySetupForCardSet(otr_card_set_); |
| 197 EXPECT_GT([main_card_set_ cardSize].width, 0U); |
| 198 EXPECT_GT([main_card_set_ cardSize].height, 0U); |
| 199 |
| 200 // Incognito should always be right of (or below in landscape) the main set. |
| 201 EXPECT_GT([otr_card_set_ layoutAxisPosition], |
| 202 [main_card_set_ layoutAxisPosition]); |
| 203 } |
| 204 |
| 205 TEST_F(StackViewControllerTest, IncognitoHandling) { |
| 206 EXPECT_FALSE([view_controller_ isCurrentSetIncognito]); |
| 207 EXPECT_EQ((CardSet*)otr_card_set_.get(), [view_controller_ inactiveCardSet]); |
| 208 [view_controller_ setActiveCardSet:[view_controller_ inactiveCardSet]]; |
| 209 EXPECT_TRUE([view_controller_ isCurrentSetIncognito]); |
| 210 EXPECT_EQ((CardSet*)main_card_set_.get(), [view_controller_ inactiveCardSet]); |
| 211 // Incognito should always be right of (or below in landscape) the main set. |
| 212 EXPECT_GT([otr_card_set_ layoutAxisPosition], |
| 213 [main_card_set_ layoutAxisPosition]); |
| 214 } |
| 215 |
| 216 TEST_F(StackViewControllerTest, ScrollViewContentOffsetRecentering) { |
| 217 BOOL is_portrait = UIInterfaceOrientationIsPortrait( |
| 218 [UIApplication sharedApplication].statusBarOrientation); |
| 219 CGFloat scroll_view_breadth = |
| 220 is_portrait ? [[view_controller_ scrollView] contentSize].width |
| 221 : [[view_controller_ scrollView] contentSize].height; |
| 222 CGFloat content_size = |
| 223 is_portrait ? [[view_controller_ scrollView] contentSize].height |
| 224 : [[view_controller_ scrollView] contentSize].width; |
| 225 |
| 226 // Test that recentering occurs after content offset gets set to lower |
| 227 // boundary. |
| 228 CGPoint newContentOffset = is_portrait ? CGPointMake(scroll_view_breadth, 0) |
| 229 : CGPointMake(0, scroll_view_breadth); |
| 230 [[view_controller_ scrollView] setContentOffset:newContentOffset]; |
| 231 [view_controller_ recenterScrollViewIfNecessary]; |
| 232 CGFloat content_offset = |
| 233 is_portrait ? [[view_controller_ scrollView] contentOffset].y |
| 234 : [[view_controller_ scrollView] contentOffset].x; |
| 235 EXPECT_GT(content_offset, 0); |
| 236 EXPECT_LT(content_offset, content_size); |
| 237 ValidateDisplaySetupForCardSet(main_card_set_); |
| 238 ValidateDisplaySetupForCardSet(otr_card_set_); |
| 239 |
| 240 // Test that recentering occurs after content offset gets set to upper |
| 241 // boundary. |
| 242 newContentOffset = is_portrait |
| 243 ? CGPointMake(scroll_view_breadth, content_size) |
| 244 : CGPointMake(content_size, scroll_view_breadth); |
| 245 [[view_controller_ scrollView] setContentOffset:newContentOffset]; |
| 246 [view_controller_ recenterScrollViewIfNecessary]; |
| 247 content_offset = is_portrait |
| 248 ? [[view_controller_ scrollView] contentOffset].y |
| 249 : [[view_controller_ scrollView] contentOffset].x; |
| 250 EXPECT_GT(content_offset, 0); |
| 251 EXPECT_LT(content_offset, content_size); |
| 252 ValidateDisplaySetupForCardSet(main_card_set_); |
| 253 ValidateDisplaySetupForCardSet(otr_card_set_); |
| 254 } |
| 255 |
| 256 TEST_F(StackViewControllerTest, TabModelReset) { |
| 257 [view_controller_ setOtrTabModel:nil]; |
| 258 ValidateDisplaySetupForCardSet(main_card_set_); |
| 259 ValidateDisplaySetupForCardSet(otr_card_set_); |
| 260 } |
| 261 |
| 262 } // namespace |
OLD | NEW |