1 // Copyright 2014 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 "base/mac/scoped_objc_class_swizzler.h"
7 #import "base/mac/scoped_nsobject.h"
8 #include "testing/gtest/include/gtest/gtest.h"
10 @interface ObjCClassSwizzlerTestOne : NSObject
11 + (NSInteger)function;
13 - (NSInteger)modifier;
16 @interface ObjCClassSwizzlerTestTwo : NSObject
17 + (NSInteger)function;
19 - (NSInteger)modifier;
22 @implementation ObjCClassSwizzlerTestOne : NSObject
24 + (NSInteger)function {
29 // Multiply by a modifier to ensure |self| in a swizzled implementation
30 // refers to the original object.
31 return 1 * [self modifier];
34 - (NSInteger)modifier {
40 @implementation ObjCClassSwizzlerTestTwo : NSObject
42 + (NSInteger)function {
47 return 2 * [self modifier];
50 - (NSInteger)modifier {
56 @interface ObjCClassSwizzlerTestOne (AlternateCategory)
57 - (NSInteger)alternate;
60 @implementation ObjCClassSwizzlerTestOne (AlternateCategory)
61 - (NSInteger)alternate {
62 return 3 * [self modifier];
66 @interface ObjCClassSwizzlerTestOneChild : ObjCClassSwizzlerTestOne
67 - (NSInteger)childAlternate;
70 @implementation ObjCClassSwizzlerTestOneChild
71 - (NSInteger)childAlternate {
72 return 5 * [self modifier];
79 TEST(ObjCClassSwizzlerTest, SwizzleInstanceMethods) {
80 base::scoped_nsobject<ObjCClassSwizzlerTestOne> object_one(
81 [[ObjCClassSwizzlerTestOne alloc] init]);
82 base::scoped_nsobject<ObjCClassSwizzlerTestTwo> object_two(
83 [[ObjCClassSwizzlerTestTwo alloc] init]);
84 EXPECT_EQ(3, [object_one method]);
85 EXPECT_EQ(14, [object_two method]);
88 base::mac::ScopedObjCClassSwizzler swizzler(
89 [ObjCClassSwizzlerTestOne class],
90 [ObjCClassSwizzlerTestTwo class],
92 EXPECT_EQ(6, [object_one method]);
93 EXPECT_EQ(7, [object_two method]);
95 IMP original = swizzler.GetOriginalImplementation();
96 id expected_result = reinterpret_cast<id>(3);
97 EXPECT_EQ(expected_result, original(object_one, @selector(method)));
100 EXPECT_EQ(3, [object_one method]);
101 EXPECT_EQ(14, [object_two method]);
104 TEST(ObjCClassSwizzlerTest, SwizzleClassMethods) {
105 EXPECT_EQ(10, [ObjCClassSwizzlerTestOne function]);
106 EXPECT_EQ(20, [ObjCClassSwizzlerTestTwo function]);
109 base::mac::ScopedObjCClassSwizzler swizzler(
110 [ObjCClassSwizzlerTestOne class],
111 [ObjCClassSwizzlerTestTwo class],
112 @selector(function));
113 EXPECT_EQ(20, [ObjCClassSwizzlerTestOne function]);
114 EXPECT_EQ(10, [ObjCClassSwizzlerTestTwo function]);
116 IMP original = swizzler.GetOriginalImplementation();
117 id expected_result = reinterpret_cast<id>(10);
118 EXPECT_EQ(expected_result, original(nil, @selector(function)));
121 EXPECT_EQ(10, [ObjCClassSwizzlerTestOne function]);
122 EXPECT_EQ(20, [ObjCClassSwizzlerTestTwo function]);
125 TEST(ObjCClassSwizzlerTest, SwizzleViaCategory) {
126 base::scoped_nsobject<ObjCClassSwizzlerTestOne> object_one(
127 [[ObjCClassSwizzlerTestOne alloc] init]);
128 EXPECT_EQ(3, [object_one method]);
131 base::mac::ScopedObjCClassSwizzler swizzler(
132 [ObjCClassSwizzlerTestOne class],
134 @selector(alternate));
135 EXPECT_EQ(9, [object_one method]);
137 IMP original = swizzler.GetOriginalImplementation();
138 id expected_result = reinterpret_cast<id>(3);
139 EXPECT_EQ(expected_result, original(object_one, @selector(method)));
142 EXPECT_EQ(3, [object_one method]);
145 TEST(ObjCClassSwizzlerTest, SwizzleViaInheritance) {
146 base::scoped_nsobject<ObjCClassSwizzlerTestOneChild> child(
147 [[ObjCClassSwizzlerTestOneChild alloc] init]);
148 EXPECT_EQ(3, [child method]);
151 base::mac::ScopedObjCClassSwizzler swizzler(
152 [ObjCClassSwizzlerTestOneChild class],
154 @selector(childAlternate));
155 EXPECT_EQ(15, [child method]);
157 IMP original = swizzler.GetOriginalImplementation();
158 id expected_result = reinterpret_cast<id>(3);
159 EXPECT_EQ(expected_result, original(child, @selector(method)));
162 EXPECT_EQ(3, [child method]);