// Copyright (c) 2009 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #import <Foundation/Foundation.h> #import <objc/objc-class.h> #import "chrome/browser/cocoa/keystone_glue.h" #include "testing/gtest/include/gtest/gtest.h" #include "testing/platform_test.h" @interface FakeGlueRegistration : NSObject @end @implementation FakeGlueRegistration // Send the notifications that a real KeystoneGlue object would send. - (void)checkForUpdate { NSNumber* yesNumber = [NSNumber numberWithBool:YES]; NSString* statusKey = @"Status"; NSDictionary* dictionary = [NSDictionary dictionaryWithObject:yesNumber forKey:statusKey]; NSNotificationCenter* center = [NSNotificationCenter defaultCenter]; [center postNotificationName:@"KSRegistrationCheckForUpdateNotification" object:nil userInfo:dictionary]; } - (void)startUpdate { NSNotificationCenter* center = [NSNotificationCenter defaultCenter]; [center postNotificationName:@"KSRegistrationStartUpdateNotification" object:nil]; } @end @interface FakeKeystoneGlue : KeystoneGlue { @public BOOL upToDate_; NSString *latestVersion_; BOOL successful_; int installs_; } - (void)fakeAboutWindowCallback:(NSNotification*)notification; @end @implementation FakeKeystoneGlue - (id)init { if ((self = [super init])) { // some lies upToDate_ = YES; latestVersion_ = @"foo bar"; successful_ = YES; installs_ = 1010101010; // Set up an observer that takes the notification that the About window // listens for. NSNotificationCenter* center = [NSNotificationCenter defaultCenter]; [center addObserver:self selector:@selector(fakeAboutWindowCallback:) name:kAutoupdateStatusNotification object:nil]; } return self; } - (void)dealloc { [[NSNotificationCenter defaultCenter] removeObserver:self]; [super dealloc]; } // For mocking - (NSDictionary*)infoDictionary { NSDictionary* dict = [NSDictionary dictionaryWithObjectsAndKeys: @"http://foo.bar", @"KSUpdateURL", @"com.google.whatever", @"KSProductID", @"0.0.0.1", @"KSVersion", nil]; return dict; } // For mocking - (BOOL)loadKeystoneRegistration { return YES; } // Confirms certain things are happy - (BOOL)dictReadCorrectly { return ([url_ isEqual:@"http://foo.bar"] && [productID_ isEqual:@"com.google.whatever"] && [version_ isEqual:@"0.0.0.1"]); } // Confirms certain things are happy - (BOOL)hasATimer { return timer_ ? YES : NO; } - (void)addFakeRegistration { registration_ = [[FakeGlueRegistration alloc] init]; } - (void)fakeAboutWindowCallback:(NSNotification*)notification { NSDictionary* dictionary = [notification userInfo]; AutoupdateStatus status = static_cast<AutoupdateStatus>( [[dictionary objectForKey:kAutoupdateStatusStatus] intValue]); if (status == kAutoupdateAvailable) { upToDate_ = NO; latestVersion_ = [dictionary objectForKey:kAutoupdateStatusVersion]; } else if (status == kAutoupdateInstallFailed) { successful_ = NO; installs_ = 0; } } // Confirm we look like callbacks with nil NSNotifications - (BOOL)confirmCallbacks { return (!upToDate_ && (latestVersion_ == nil) && !successful_ && (installs_ == 0)); } @end namespace { class KeystoneGlueTest : public PlatformTest { }; // DISABLED because the mocking isn't currently working. TEST_F(KeystoneGlueTest, DISABLED_BasicGlobalCreate) { // Allow creation of a KeystoneGlue by mocking out a few calls SEL ids = @selector(infoDictionary); IMP oldInfoImp_ = [[KeystoneGlue class] instanceMethodForSelector:ids]; IMP newInfoImp_ = [[FakeKeystoneGlue class] instanceMethodForSelector:ids]; Method infoMethod_ = class_getInstanceMethod([KeystoneGlue class], ids); method_setImplementation(infoMethod_, newInfoImp_); SEL lks = @selector(loadKeystoneRegistration); IMP oldLoadImp_ = [[KeystoneGlue class] instanceMethodForSelector:lks]; IMP newLoadImp_ = [[FakeKeystoneGlue class] instanceMethodForSelector:lks]; Method loadMethod_ = class_getInstanceMethod([KeystoneGlue class], lks); method_setImplementation(loadMethod_, newLoadImp_); KeystoneGlue *glue = [KeystoneGlue defaultKeystoneGlue]; ASSERT_TRUE(glue); // Fix back up the class to the way we found it. method_setImplementation(infoMethod_, oldInfoImp_); method_setImplementation(loadMethod_, oldLoadImp_); } // DISABLED because the mocking isn't currently working. TEST_F(KeystoneGlueTest, DISABLED_BasicUse) { FakeKeystoneGlue* glue = [[[FakeKeystoneGlue alloc] init] autorelease]; [glue loadParameters]; ASSERT_TRUE([glue dictReadCorrectly]); // Likely returns NO in the unit test, but call it anyway to make // sure it doesn't crash. [glue loadKeystoneRegistration]; // Confirm we start up an active timer [glue registerWithKeystone]; ASSERT_TRUE([glue hasATimer]); [glue stopTimer]; // Brief exercise of callbacks [glue addFakeRegistration]; [glue checkForUpdate]; [glue installUpdate]; ASSERT_TRUE([glue confirmCallbacks]); } } // namespace