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 {
42 - (BOOL)setActiveWithReportingAttributes:(NSArray*)reportingAttributes
43 error:(NSError**)error {
47 - (void)checkForUpdateWasUserInitiated:(BOOL)userInitiated {
53 - (ksr::KSRegistrationTicketType)ticketType {
54 return ksr::kKSRegistrationDontKnowWhatKindOfTicket;
60 @implementation FakeKeystoneRegistration
62 // Send the notifications that a real KeystoneGlue object would send.
64 - (void)checkForUpdateWasUserInitiated:(BOOL)userInitiated {
65 NSNumber* yesNumber = [NSNumber numberWithBool:YES];
66 NSString* statusKey = @"Status";
67 NSDictionary* dictionary = [NSDictionary dictionaryWithObject:yesNumber
69 NSNotificationCenter* center = [NSNotificationCenter defaultCenter];
70 [center postNotificationName:ksr::KSRegistrationCheckForUpdateNotification
76 NSNotificationCenter* center = [NSNotificationCenter defaultCenter];
77 [center postNotificationName:ksr::KSRegistrationStartUpdateNotification
84 @interface FakeKeystoneGlue : KeystoneGlue {
87 NSString *latestVersion_;
92 - (void)fakeAboutWindowCallback:(NSNotification*)notification;
96 @implementation FakeKeystoneGlue
99 if ((self = [super init])) {
102 latestVersion_ = @"foo bar";
104 installs_ = 1010101010;
106 // Set up an observer that takes the notification that the About window
108 NSNotificationCenter* center = [NSNotificationCenter defaultCenter];
109 [center addObserver:self
110 selector:@selector(fakeAboutWindowCallback:)
111 name:kAutoupdateStatusNotification
118 [[NSNotificationCenter defaultCenter] removeObserver:self];
123 - (NSDictionary*)infoDictionary {
124 NSDictionary* dict = [NSDictionary dictionaryWithObjectsAndKeys:
125 @"http://foo.bar", @"KSUpdateURL",
126 @"com.google.whatever", @"KSProductID",
127 @"0.0.0.1", @"KSVersion",
133 - (BOOL)loadKeystoneRegistration {
137 // Confirms certain things are happy
138 - (BOOL)dictReadCorrectly {
139 return ([url_ isEqual:@"http://foo.bar"] &&
140 [productID_ isEqual:@"com.google.whatever"] &&
141 [version_ isEqual:@"0.0.0.1"]);
144 // Confirms certain things are happy
146 return timer_ ? YES : NO;
149 - (void)addFakeRegistration {
150 registration_ = [[FakeKeystoneRegistration alloc] init];
153 - (void)fakeAboutWindowCallback:(NSNotification*)notification {
154 NSDictionary* dictionary = [notification userInfo];
155 AutoupdateStatus status = static_cast<AutoupdateStatus>(
156 [[dictionary objectForKey:kAutoupdateStatusStatus] intValue]);
158 if (status == kAutoupdateAvailable) {
160 latestVersion_ = [dictionary objectForKey:kAutoupdateStatusVersion];
161 } else if (status == kAutoupdateInstallFailed) {
167 // Confirm we look like callbacks with nil NSNotifications
168 - (BOOL)confirmCallbacks {
169 return (!upToDate_ &&
170 (latestVersion_ == nil) &&
180 class KeystoneGlueTest : public PlatformTest {
183 // DISABLED because the mocking isn't currently working.
184 TEST_F(KeystoneGlueTest, DISABLED_BasicGlobalCreate) {
185 // Allow creation of a KeystoneGlue by mocking out a few calls
186 SEL ids = @selector(infoDictionary);
187 IMP oldInfoImp_ = [[KeystoneGlue class] instanceMethodForSelector:ids];
188 IMP newInfoImp_ = [[FakeKeystoneGlue class] instanceMethodForSelector:ids];
189 Method infoMethod_ = class_getInstanceMethod([KeystoneGlue class], ids);
190 method_setImplementation(infoMethod_, newInfoImp_);
192 SEL lks = @selector(loadKeystoneRegistration);
193 IMP oldLoadImp_ = [[KeystoneGlue class] instanceMethodForSelector:lks];
194 IMP newLoadImp_ = [[FakeKeystoneGlue class] instanceMethodForSelector:lks];
195 Method loadMethod_ = class_getInstanceMethod([KeystoneGlue class], lks);
196 method_setImplementation(loadMethod_, newLoadImp_);
198 KeystoneGlue *glue = [KeystoneGlue defaultKeystoneGlue];
201 // Fix back up the class to the way we found it.
202 method_setImplementation(infoMethod_, oldInfoImp_);
203 method_setImplementation(loadMethod_, oldLoadImp_);
206 // DISABLED because the mocking isn't currently working.
207 TEST_F(KeystoneGlueTest, DISABLED_BasicUse) {
208 FakeKeystoneGlue* glue = [[[FakeKeystoneGlue alloc] init] autorelease];
209 [glue loadParameters];
210 ASSERT_TRUE([glue dictReadCorrectly]);
212 // Likely returns NO in the unit test, but call it anyway to make
213 // sure it doesn't crash.
214 [glue loadKeystoneRegistration];
216 // Confirm we start up an active timer
217 [glue registerWithKeystone];
218 ASSERT_TRUE([glue hasATimer]);
221 // Brief exercise of callbacks
222 [glue addFakeRegistration];
223 [glue checkForUpdate];
224 [glue installUpdate];
225 ASSERT_TRUE([glue confirmCallbacks]);