1// Copyright (c) 2011 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 <Cocoa/Cocoa.h> 6 7#include "base/memory/scoped_nsobject.h" 8#include "chrome/browser/themes/theme_service.h" 9#import "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_controller.h" 10#import "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_toolbar_view.h" 11#import "chrome/browser/ui/cocoa/cocoa_test_helper.h" 12#include "grit/theme_resources.h" 13#include "testing/gmock/include/gmock/gmock.h" 14#include "testing/gtest/include/gtest/gtest.h" 15#include "testing/platform_test.h" 16#include "third_party/skia/include/core/SkBitmap.h" 17#include "third_party/skia/include/core/SkColor.h" 18#include "ui/base/theme_provider.h" 19 20using ::testing::_; 21using ::testing::DoAll; 22using ::testing::Return; 23using ::testing::SetArgumentPointee; 24 25// When testing the floating drawing, we need to have a source of theme data. 26class MockThemeProvider : public ui::ThemeProvider { 27 public: 28 // Cross platform methods 29 MOCK_METHOD1(Init, void(Profile*)); 30 MOCK_CONST_METHOD1(GetBitmapNamed, SkBitmap*(int)); 31 MOCK_CONST_METHOD1(GetColor, SkColor(int)); 32 MOCK_CONST_METHOD2(GetDisplayProperty, bool(int, int*)); 33 MOCK_CONST_METHOD0(ShouldUseNativeFrame, bool()); 34 MOCK_CONST_METHOD1(HasCustomImage, bool(int)); 35 MOCK_CONST_METHOD1(GetRawData, RefCountedMemory*(int)); 36 37 // OSX stuff 38 MOCK_CONST_METHOD2(GetNSImageNamed, NSImage*(int, bool)); 39 MOCK_CONST_METHOD2(GetNSImageColorNamed, NSColor*(int, bool)); 40 MOCK_CONST_METHOD2(GetNSColor, NSColor*(int, bool)); 41 MOCK_CONST_METHOD2(GetNSColorTint, NSColor*(int, bool)); 42 MOCK_CONST_METHOD1(GetNSGradient, NSGradient*(int)); 43}; 44 45// Allows us to inject our fake controller below. 46@interface BookmarkBarToolbarView (TestingAPI) 47-(void)setController:(id<BookmarkBarToolbarViewController>)controller; 48@end 49 50@implementation BookmarkBarToolbarView (TestingAPI) 51-(void)setController:(id<BookmarkBarToolbarViewController>)controller { 52 controller_ = controller; 53} 54@end 55 56// Allows us to control which way the view is rendered. 57@interface DrawDetachedBarFakeController : 58 NSObject<BookmarkBarState, BookmarkBarToolbarViewController> { 59 @private 60 int currentTabContentsHeight_; 61 ui::ThemeProvider* themeProvider_; 62 bookmarks::VisualState visualState_; 63} 64@property (nonatomic, assign) int currentTabContentsHeight; 65@property (nonatomic, assign) ui::ThemeProvider* themeProvider; 66@property (nonatomic, assign) bookmarks::VisualState visualState; 67 68// |BookmarkBarState| protocol: 69- (BOOL)isVisible; 70- (BOOL)isAnimationRunning; 71- (BOOL)isInState:(bookmarks::VisualState)state; 72- (BOOL)isAnimatingToState:(bookmarks::VisualState)state; 73- (BOOL)isAnimatingFromState:(bookmarks::VisualState)state; 74- (BOOL)isAnimatingFromState:(bookmarks::VisualState)fromState 75 toState:(bookmarks::VisualState)toState; 76- (BOOL)isAnimatingBetweenState:(bookmarks::VisualState)fromState 77 andState:(bookmarks::VisualState)toState; 78- (CGFloat)detachedMorphProgress; 79@end 80 81@implementation DrawDetachedBarFakeController 82@synthesize currentTabContentsHeight = currentTabContentsHeight_; 83@synthesize themeProvider = themeProvider_; 84@synthesize visualState = visualState_; 85 86- (id)init { 87 if ((self = [super init])) { 88 [self setVisualState:bookmarks::kHiddenState]; 89 } 90 return self; 91} 92 93- (BOOL)isVisible { return YES; } 94- (BOOL)isAnimationRunning { return NO; } 95- (BOOL)isInState:(bookmarks::VisualState)state 96 { return ([self visualState] == state) ? YES : NO; } 97- (BOOL)isAnimatingToState:(bookmarks::VisualState)state { return NO; } 98- (BOOL)isAnimatingFromState:(bookmarks::VisualState)state { return NO; } 99- (BOOL)isAnimatingFromState:(bookmarks::VisualState)fromState 100 toState:(bookmarks::VisualState)toState { return NO; } 101- (BOOL)isAnimatingBetweenState:(bookmarks::VisualState)fromState 102 andState:(bookmarks::VisualState)toState { return NO; } 103- (CGFloat)detachedMorphProgress { return 1; } 104@end 105 106class BookmarkBarToolbarViewTest : public CocoaTest { 107 public: 108 BookmarkBarToolbarViewTest() { 109 controller_.reset([[DrawDetachedBarFakeController alloc] init]); 110 NSRect frame = NSMakeRect(0, 0, 400, 40); 111 scoped_nsobject<BookmarkBarToolbarView> view( 112 [[BookmarkBarToolbarView alloc] initWithFrame:frame]); 113 view_ = view.get(); 114 [[test_window() contentView] addSubview:view_]; 115 [view_ setController:controller_.get()]; 116 } 117 118 scoped_nsobject<DrawDetachedBarFakeController> controller_; 119 BookmarkBarToolbarView* view_; 120}; 121 122TEST_VIEW(BookmarkBarToolbarViewTest, view_) 123 124// Test drawing (part 1), mostly to ensure nothing leaks or crashes. 125TEST_F(BookmarkBarToolbarViewTest, DisplayAsNormalBar) { 126 [controller_.get() setVisualState:bookmarks::kShowingState]; 127 [view_ display]; 128} 129 130// Test drawing (part 2), mostly to ensure nothing leaks or crashes. 131TEST_F(BookmarkBarToolbarViewTest, DisplayAsDetachedBarWithNoImage) { 132 [controller_.get() setVisualState:bookmarks::kDetachedState]; 133 134 // Tests where we don't have a background image, only a color. 135 MockThemeProvider provider; 136 EXPECT_CALL(provider, GetColor(ThemeService::COLOR_NTP_BACKGROUND)) 137 .WillRepeatedly(Return(SK_ColorWHITE)); 138 EXPECT_CALL(provider, HasCustomImage(IDR_THEME_NTP_BACKGROUND)) 139 .WillRepeatedly(Return(false)); 140 [controller_.get() setThemeProvider:&provider]; 141 142 [view_ display]; 143} 144 145// Actions used in DisplayAsDetachedBarWithBgImage. 146ACTION(SetBackgroundTiling) { 147 *arg1 = ThemeService::NO_REPEAT; 148 return true; 149} 150 151ACTION(SetAlignLeft) { 152 *arg1 = ThemeService::ALIGN_LEFT; 153 return true; 154} 155 156// Test drawing (part 3), mostly to ensure nothing leaks or crashes. 157TEST_F(BookmarkBarToolbarViewTest, DisplayAsDetachedBarWithBgImage) { 158 [controller_.get() setVisualState:bookmarks::kDetachedState]; 159 160 // Tests where we have a background image, with positioning information. 161 MockThemeProvider provider; 162 163 // Advertise having an image. 164 EXPECT_CALL(provider, GetColor(ThemeService::COLOR_NTP_BACKGROUND)) 165 .WillRepeatedly(Return(SK_ColorRED)); 166 EXPECT_CALL(provider, HasCustomImage(IDR_THEME_NTP_BACKGROUND)) 167 .WillRepeatedly(Return(true)); 168 169 // Return the correct tiling/alignment information. 170 EXPECT_CALL(provider, 171 GetDisplayProperty(ThemeService::NTP_BACKGROUND_TILING, _)) 172 .WillRepeatedly(SetBackgroundTiling()); 173 EXPECT_CALL(provider, 174 GetDisplayProperty(ThemeService::NTP_BACKGROUND_ALIGNMENT, _)) 175 .WillRepeatedly(SetAlignLeft()); 176 177 // Create a dummy bitmap full of not-red to blit with. 178 SkBitmap fake_bg; 179 fake_bg.setConfig(SkBitmap::kARGB_8888_Config, 800, 800); 180 fake_bg.allocPixels(); 181 fake_bg.eraseColor(SK_ColorGREEN); 182 EXPECT_CALL(provider, GetBitmapNamed(IDR_THEME_NTP_BACKGROUND)) 183 .WillRepeatedly(Return(&fake_bg)); 184 185 [controller_.get() setThemeProvider:&provider]; 186 [controller_.get() setCurrentTabContentsHeight:200]; 187 188 [view_ display]; 189} 190 191// TODO(viettrungluu): write more unit tests, especially after my refactoring. 192