blob: 79820a3ffa5fb8e79a6d9aacf3ca76bb8c31740d [file] [log] [blame]
// Copyright 2014 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 "base/mac/scoped_objc_class_swizzler.h"
#import "base/mac/scoped_nsobject.h"
#include "testing/gtest/include/gtest/gtest.h"
@interface ObjCClassSwizzlerTestOne : NSObject
+ (NSInteger)function;
- (NSInteger)method;
- (NSInteger)modifier;
@end
@interface ObjCClassSwizzlerTestTwo : NSObject
+ (NSInteger)function;
- (NSInteger)method;
- (NSInteger)modifier;
@end
@implementation ObjCClassSwizzlerTestOne : NSObject
+ (NSInteger)function {
return 10;
}
- (NSInteger)method {
// Multiply by a modifier to ensure |self| in a swizzled implementation
// refers to the original object.
return 1 * [self modifier];
}
- (NSInteger)modifier {
return 3;
}
@end
@implementation ObjCClassSwizzlerTestTwo : NSObject
+ (NSInteger)function {
return 20;
}
- (NSInteger)method {
return 2 * [self modifier];
}
- (NSInteger)modifier {
return 7;
}
@end
@interface ObjCClassSwizzlerTestOne (AlternateCategory)
- (NSInteger)alternate;
@end
@implementation ObjCClassSwizzlerTestOne (AlternateCategory)
- (NSInteger)alternate {
return 3 * [self modifier];
}
@end
@interface ObjCClassSwizzlerTestOneChild : ObjCClassSwizzlerTestOne
- (NSInteger)childAlternate;
@end
@implementation ObjCClassSwizzlerTestOneChild
- (NSInteger)childAlternate {
return 5 * [self modifier];
}
@end
namespace base {
namespace mac {
TEST(ObjCClassSwizzlerTest, SwizzleInstanceMethods) {
base::scoped_nsobject<ObjCClassSwizzlerTestOne> object_one(
[[ObjCClassSwizzlerTestOne alloc] init]);
base::scoped_nsobject<ObjCClassSwizzlerTestTwo> object_two(
[[ObjCClassSwizzlerTestTwo alloc] init]);
EXPECT_EQ(3, [object_one method]);
EXPECT_EQ(14, [object_two method]);
{
base::mac::ScopedObjCClassSwizzler swizzler(
[ObjCClassSwizzlerTestOne class],
[ObjCClassSwizzlerTestTwo class],
@selector(method));
EXPECT_EQ(6, [object_one method]);
EXPECT_EQ(7, [object_two method]);
IMP original = swizzler.GetOriginalImplementation();
id expected_result = reinterpret_cast<id>(3);
EXPECT_EQ(expected_result, original(object_one, @selector(method)));
}
EXPECT_EQ(3, [object_one method]);
EXPECT_EQ(14, [object_two method]);
}
TEST(ObjCClassSwizzlerTest, SwizzleClassMethods) {
EXPECT_EQ(10, [ObjCClassSwizzlerTestOne function]);
EXPECT_EQ(20, [ObjCClassSwizzlerTestTwo function]);
{
base::mac::ScopedObjCClassSwizzler swizzler(
[ObjCClassSwizzlerTestOne class],
[ObjCClassSwizzlerTestTwo class],
@selector(function));
EXPECT_EQ(20, [ObjCClassSwizzlerTestOne function]);
EXPECT_EQ(10, [ObjCClassSwizzlerTestTwo function]);
IMP original = swizzler.GetOriginalImplementation();
id expected_result = reinterpret_cast<id>(10);
EXPECT_EQ(expected_result,
original([ObjCClassSwizzlerTestOne class], @selector(function)));
}
EXPECT_EQ(10, [ObjCClassSwizzlerTestOne function]);
EXPECT_EQ(20, [ObjCClassSwizzlerTestTwo function]);
}
TEST(ObjCClassSwizzlerTest, SwizzleViaCategory) {
base::scoped_nsobject<ObjCClassSwizzlerTestOne> object_one(
[[ObjCClassSwizzlerTestOne alloc] init]);
EXPECT_EQ(3, [object_one method]);
{
base::mac::ScopedObjCClassSwizzler swizzler(
[ObjCClassSwizzlerTestOne class],
@selector(method),
@selector(alternate));
EXPECT_EQ(9, [object_one method]);
IMP original = swizzler.GetOriginalImplementation();
id expected_result = reinterpret_cast<id>(3);
EXPECT_EQ(expected_result, original(object_one, @selector(method)));
}
EXPECT_EQ(3, [object_one method]);
}
TEST(ObjCClassSwizzlerTest, SwizzleViaInheritance) {
base::scoped_nsobject<ObjCClassSwizzlerTestOneChild> child(
[[ObjCClassSwizzlerTestOneChild alloc] init]);
EXPECT_EQ(3, [child method]);
{
base::mac::ScopedObjCClassSwizzler swizzler(
[ObjCClassSwizzlerTestOneChild class],
@selector(method),
@selector(childAlternate));
EXPECT_EQ(15, [child method]);
IMP original = swizzler.GetOriginalImplementation();
id expected_result = reinterpret_cast<id>(3);
EXPECT_EQ(expected_result, original(child, @selector(method)));
}
EXPECT_EQ(3, [child method]);
}
} // namespace mac
} // namespace base