// Copyright 2015 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/test/base/scoped_bundle_swizzler_mac.h"
#import <Foundation/Foundation.h>
#include <memory>
#include "base/apple/foundation_util.h"
#include "base/apple/scoped_objc_class_swizzler.h"
#include "base/check.h"
#include "base/strings/sys_string_conversions.h"
static id __strong g_swizzled_main_bundle = nil;
// A donor class that provides a +[NSBundle mainBundle] method that can be
// swapped with NSBundle.
@interface TestBundle : NSProxy
- (instancetype)initWithRealBundle:(NSBundle*)bundle;
+ (NSBundle*)mainBundle;
@end
@implementation TestBundle {
NSBundle* __strong _mainBundle;
NSString* __strong _bundleID;
}
+ (NSBundle*)mainBundle {
return g_swizzled_main_bundle;
}
- (instancetype)initWithRealBundle:(NSBundle*)bundle {
_mainBundle = bundle;
_bundleID = base::SysUTF8ToNSString(base::apple::BaseBundleID());
return self;
}
- (NSString*)bundleIdentifier {
return _bundleID;
}
- (void)forwardInvocation:(NSInvocation*)invocation {
invocation.target = _mainBundle;
[invocation invoke];
}
- (NSMethodSignature*)methodSignatureForSelector:(SEL)sel {
return [_mainBundle methodSignatureForSelector:sel];
}
@end
ScopedBundleSwizzlerMac::ScopedBundleSwizzlerMac() {
CHECK(!g_swizzled_main_bundle);
NSBundle* original_main_bundle = NSBundle.mainBundle;
g_swizzled_main_bundle =
[[TestBundle alloc] initWithRealBundle:original_main_bundle];
class_swizzler_ = std::make_unique<base::apple::ScopedObjCClassSwizzler>(
[NSBundle class], [TestBundle class], @selector(mainBundle));
}
ScopedBundleSwizzlerMac::~ScopedBundleSwizzlerMac() {
g_swizzled_main_bundle = nil;
}