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