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 <Foundation/Foundation.h> 6#import <objc/objc-class.h> 7 8#import "chrome/browser/mac/keystone_glue.h" 9#import "chrome/browser/mac/keystone_registration.h" 10#include "testing/gtest/include/gtest/gtest.h" 11#include "testing/platform_test.h" 12 13namespace ksr = keystone_registration; 14 15 16@interface FakeKeystoneRegistration : KSRegistration 17@end 18 19 20// This unit test implements FakeKeystoneRegistration as a KSRegistration 21// subclass. It won't be linked against KSRegistration, so provide a stub 22// KSRegistration class on which to base FakeKeystoneRegistration. 23@implementation KSRegistration 24 25+ (id)registrationWithProductID:(NSString*)productID { 26 return nil; 27} 28 29- (BOOL)registerWithParameters:(NSDictionary*)args { 30 return NO; 31} 32 33- (BOOL)promoteWithParameters:(NSDictionary*)args 34 authorization:(AuthorizationRef)authorization { 35 return NO; 36} 37 38- (BOOL)setActive { 39 return NO; 40} 41 42- (void)checkForUpdateWasUserInitiated:(BOOL)userInitiated { 43} 44 45- (void)startUpdate { 46} 47 48- (ksr::KSRegistrationTicketType)ticketType { 49 return ksr::kKSRegistrationDontKnowWhatKindOfTicket; 50} 51 52@end 53 54 55@implementation FakeKeystoneRegistration 56 57// Send the notifications that a real KeystoneGlue object would send. 58 59- (void)checkForUpdateWasUserInitiated:(BOOL)userInitiated { 60 NSNumber* yesNumber = [NSNumber numberWithBool:YES]; 61 NSString* statusKey = @"Status"; 62 NSDictionary* dictionary = [NSDictionary dictionaryWithObject:yesNumber 63 forKey:statusKey]; 64 NSNotificationCenter* center = [NSNotificationCenter defaultCenter]; 65 [center postNotificationName:ksr::KSRegistrationCheckForUpdateNotification 66 object:nil 67 userInfo:dictionary]; 68} 69 70- (void)startUpdate { 71 NSNotificationCenter* center = [NSNotificationCenter defaultCenter]; 72 [center postNotificationName:ksr::KSRegistrationStartUpdateNotification 73 object:nil]; 74} 75 76@end 77 78 79@interface FakeKeystoneGlue : KeystoneGlue { 80 @public 81 BOOL upToDate_; 82 NSString *latestVersion_; 83 BOOL successful_; 84 int installs_; 85} 86 87- (void)fakeAboutWindowCallback:(NSNotification*)notification; 88@end 89 90 91@implementation FakeKeystoneGlue 92 93- (id)init { 94 if ((self = [super init])) { 95 // some lies 96 upToDate_ = YES; 97 latestVersion_ = @"foo bar"; 98 successful_ = YES; 99 installs_ = 1010101010; 100 101 // Set up an observer that takes the notification that the About window 102 // listens for. 103 NSNotificationCenter* center = [NSNotificationCenter defaultCenter]; 104 [center addObserver:self 105 selector:@selector(fakeAboutWindowCallback:) 106 name:kAutoupdateStatusNotification 107 object:nil]; 108 } 109 return self; 110} 111 112- (void)dealloc { 113 [[NSNotificationCenter defaultCenter] removeObserver:self]; 114 [super dealloc]; 115} 116 117// For mocking 118- (NSDictionary*)infoDictionary { 119 NSDictionary* dict = [NSDictionary dictionaryWithObjectsAndKeys: 120 @"http://foo.bar", @"KSUpdateURL", 121 @"com.google.whatever", @"KSProductID", 122 @"0.0.0.1", @"KSVersion", 123 nil]; 124 return dict; 125} 126 127// For mocking 128- (BOOL)loadKeystoneRegistration { 129 return YES; 130} 131 132// Confirms certain things are happy 133- (BOOL)dictReadCorrectly { 134 return ([url_ isEqual:@"http://foo.bar"] && 135 [productID_ isEqual:@"com.google.whatever"] && 136 [version_ isEqual:@"0.0.0.1"]); 137} 138 139// Confirms certain things are happy 140- (BOOL)hasATimer { 141 return timer_ ? YES : NO; 142} 143 144- (void)addFakeRegistration { 145 registration_ = [[FakeKeystoneRegistration alloc] init]; 146} 147 148- (void)fakeAboutWindowCallback:(NSNotification*)notification { 149 NSDictionary* dictionary = [notification userInfo]; 150 AutoupdateStatus status = static_cast<AutoupdateStatus>( 151 [[dictionary objectForKey:kAutoupdateStatusStatus] intValue]); 152 153 if (status == kAutoupdateAvailable) { 154 upToDate_ = NO; 155 latestVersion_ = [dictionary objectForKey:kAutoupdateStatusVersion]; 156 } else if (status == kAutoupdateInstallFailed) { 157 successful_ = NO; 158 installs_ = 0; 159 } 160} 161 162// Confirm we look like callbacks with nil NSNotifications 163- (BOOL)confirmCallbacks { 164 return (!upToDate_ && 165 (latestVersion_ == nil) && 166 !successful_ && 167 (installs_ == 0)); 168} 169 170@end 171 172 173namespace { 174 175class KeystoneGlueTest : public PlatformTest { 176}; 177 178// DISABLED because the mocking isn't currently working. 179TEST_F(KeystoneGlueTest, DISABLED_BasicGlobalCreate) { 180 // Allow creation of a KeystoneGlue by mocking out a few calls 181 SEL ids = @selector(infoDictionary); 182 IMP oldInfoImp_ = [[KeystoneGlue class] instanceMethodForSelector:ids]; 183 IMP newInfoImp_ = [[FakeKeystoneGlue class] instanceMethodForSelector:ids]; 184 Method infoMethod_ = class_getInstanceMethod([KeystoneGlue class], ids); 185 method_setImplementation(infoMethod_, newInfoImp_); 186 187 SEL lks = @selector(loadKeystoneRegistration); 188 IMP oldLoadImp_ = [[KeystoneGlue class] instanceMethodForSelector:lks]; 189 IMP newLoadImp_ = [[FakeKeystoneGlue class] instanceMethodForSelector:lks]; 190 Method loadMethod_ = class_getInstanceMethod([KeystoneGlue class], lks); 191 method_setImplementation(loadMethod_, newLoadImp_); 192 193 KeystoneGlue *glue = [KeystoneGlue defaultKeystoneGlue]; 194 ASSERT_TRUE(glue); 195 196 // Fix back up the class to the way we found it. 197 method_setImplementation(infoMethod_, oldInfoImp_); 198 method_setImplementation(loadMethod_, oldLoadImp_); 199} 200 201// DISABLED because the mocking isn't currently working. 202TEST_F(KeystoneGlueTest, DISABLED_BasicUse) { 203 FakeKeystoneGlue* glue = [[[FakeKeystoneGlue alloc] init] autorelease]; 204 [glue loadParameters]; 205 ASSERT_TRUE([glue dictReadCorrectly]); 206 207 // Likely returns NO in the unit test, but call it anyway to make 208 // sure it doesn't crash. 209 [glue loadKeystoneRegistration]; 210 211 // Confirm we start up an active timer 212 [glue registerWithKeystone]; 213 ASSERT_TRUE([glue hasATimer]); 214 [glue stopTimer]; 215 216 // Brief exercise of callbacks 217 [glue addFakeRegistration]; 218 [glue checkForUpdate]; 219 [glue installUpdate]; 220 ASSERT_TRUE([glue confirmCallbacks]); 221} 222 223} // namespace 224