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.
5 #import <Foundation/Foundation.h>
6 #import <objc/objc-class.h>
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"
13 namespace ksr = keystone_registration;
16 @interface FakeKeystoneRegistration : KSRegistration
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
25 + (id)registrationWithProductID:(NSString*)productID {
29 - (BOOL)registerWithParameters:(NSDictionary*)args {
33 - (BOOL)promoteWithParameters:(NSDictionary*)args
34 authorization:(AuthorizationRef)authorization {
41 - (void)checkForUpdate {
47 - (ksr::KSRegistrationTicketType)ticketType {
48 return ksr::kKSRegistrationDontKnowWhatKindOfTicket;
54 @implementation FakeKeystoneRegistration
56 // Send the notifications that a real KeystoneGlue object would send.
58 - (void)checkForUpdate {
59 NSNumber* yesNumber = [NSNumber numberWithBool:YES];
60 NSString* statusKey = @"Status";
61 NSDictionary* dictionary = [NSDictionary dictionaryWithObject:yesNumber
63 NSNotificationCenter* center = [NSNotificationCenter defaultCenter];
64 [center postNotificationName:ksr::KSRegistrationCheckForUpdateNotification
70 NSNotificationCenter* center = [NSNotificationCenter defaultCenter];
71 [center postNotificationName:ksr::KSRegistrationStartUpdateNotification
78 @interface FakeKeystoneGlue : KeystoneGlue {
81 NSString *latestVersion_;
86 - (void)fakeAboutWindowCallback:(NSNotification*)notification;
90 @implementation FakeKeystoneGlue
93 if ((self = [super init])) {
96 latestVersion_ = @"foo bar";
98 installs_ = 1010101010;
100 // Set up an observer that takes the notification that the About window
102 NSNotificationCenter* center = [NSNotificationCenter defaultCenter];
103 [center addObserver:self
104 selector:@selector(fakeAboutWindowCallback:)
105 name:kAutoupdateStatusNotification
112 [[NSNotificationCenter defaultCenter] removeObserver:self];
117 - (NSDictionary*)infoDictionary {
118 NSDictionary* dict = [NSDictionary dictionaryWithObjectsAndKeys:
119 @"http://foo.bar", @"KSUpdateURL",
120 @"com.google.whatever", @"KSProductID",
121 @"0.0.0.1", @"KSVersion",
127 - (BOOL)loadKeystoneRegistration {
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"]);
138 // Confirms certain things are happy
140 return timer_ ? YES : NO;
143 - (void)addFakeRegistration {
144 registration_ = [[FakeKeystoneRegistration alloc] init];
147 - (void)fakeAboutWindowCallback:(NSNotification*)notification {
148 NSDictionary* dictionary = [notification userInfo];
149 AutoupdateStatus status = static_cast<AutoupdateStatus>(
150 [[dictionary objectForKey:kAutoupdateStatusStatus] intValue]);
152 if (status == kAutoupdateAvailable) {
154 latestVersion_ = [dictionary objectForKey:kAutoupdateStatusVersion];
155 } else if (status == kAutoupdateInstallFailed) {
161 // Confirm we look like callbacks with nil NSNotifications
162 - (BOOL)confirmCallbacks {
163 return (!upToDate_ &&
164 (latestVersion_ == nil) &&
174 class KeystoneGlueTest : public PlatformTest {
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_);
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_);
192 KeystoneGlue *glue = [KeystoneGlue defaultKeystoneGlue];
195 // Fix back up the class to the way we found it.
196 method_setImplementation(infoMethod_, oldInfoImp_);
197 method_setImplementation(loadMethod_, oldLoadImp_);
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]);
206 // Likely returns NO in the unit test, but call it anyway to make
207 // sure it doesn't crash.
208 [glue loadKeystoneRegistration];
210 // Confirm we start up an active timer
211 [glue registerWithKeystone];
212 ASSERT_TRUE([glue hasATimer]);
215 // Brief exercise of callbacks
216 [glue addFakeRegistration];
217 [glue checkForUpdate];
218 [glue installUpdate];
219 ASSERT_TRUE([glue confirmCallbacks]);