Home | History | Annotate | Download | only in mac
      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