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