blob: eacd10518218edfbcafa3370cf9f3a547cdefa82 [file] [log] [blame]
James Robinson646469d2014-10-03 15:33:28 -07001// 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.
4
5#import "base/mac/scoped_objc_class_swizzler.h"
6
7#import "base/mac/scoped_nsobject.h"
8#include "testing/gtest/include/gtest/gtest.h"
9
10@interface ObjCClassSwizzlerTestOne : NSObject
11+ (NSInteger)function;
12- (NSInteger)method;
13- (NSInteger)modifier;
14@end
15
16@interface ObjCClassSwizzlerTestTwo : NSObject
17+ (NSInteger)function;
18- (NSInteger)method;
19- (NSInteger)modifier;
20@end
21
22@implementation ObjCClassSwizzlerTestOne : NSObject
23
24+ (NSInteger)function {
25 return 10;
26}
27
28- (NSInteger)method {
29 // Multiply by a modifier to ensure |self| in a swizzled implementation
30 // refers to the original object.
31 return 1 * [self modifier];
32}
33
34- (NSInteger)modifier {
35 return 3;
36}
37
38@end
39
40@implementation ObjCClassSwizzlerTestTwo : NSObject
41
42+ (NSInteger)function {
43 return 20;
44}
45
46- (NSInteger)method {
47 return 2 * [self modifier];
48}
49
50- (NSInteger)modifier {
51 return 7;
52}
53
54@end
55
56@interface ObjCClassSwizzlerTestOne (AlternateCategory)
57- (NSInteger)alternate;
58@end
59
60@implementation ObjCClassSwizzlerTestOne (AlternateCategory)
61- (NSInteger)alternate {
62 return 3 * [self modifier];
63}
64@end
65
66@interface ObjCClassSwizzlerTestOneChild : ObjCClassSwizzlerTestOne
67- (NSInteger)childAlternate;
68@end
69
70@implementation ObjCClassSwizzlerTestOneChild
71- (NSInteger)childAlternate {
72 return 5 * [self modifier];
73}
74@end
75
76namespace base {
77namespace mac {
78
79TEST(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]);
86
87 {
88 base::mac::ScopedObjCClassSwizzler swizzler(
89 [ObjCClassSwizzlerTestOne class],
90 [ObjCClassSwizzlerTestTwo class],
91 @selector(method));
92 EXPECT_EQ(6, [object_one method]);
93 EXPECT_EQ(7, [object_two method]);
94
95 IMP original = swizzler.GetOriginalImplementation();
96 id expected_result = reinterpret_cast<id>(3);
97 EXPECT_EQ(expected_result, original(object_one, @selector(method)));
98 }
99
100 EXPECT_EQ(3, [object_one method]);
101 EXPECT_EQ(14, [object_two method]);
102}
103
104TEST(ObjCClassSwizzlerTest, SwizzleClassMethods) {
105 EXPECT_EQ(10, [ObjCClassSwizzlerTestOne function]);
106 EXPECT_EQ(20, [ObjCClassSwizzlerTestTwo function]);
107
108 {
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]);
115
116 IMP original = swizzler.GetOriginalImplementation();
117 id expected_result = reinterpret_cast<id>(10);
118 EXPECT_EQ(expected_result, original(nil, @selector(function)));
119 }
120
121 EXPECT_EQ(10, [ObjCClassSwizzlerTestOne function]);
122 EXPECT_EQ(20, [ObjCClassSwizzlerTestTwo function]);
123}
124
125TEST(ObjCClassSwizzlerTest, SwizzleViaCategory) {
126 base::scoped_nsobject<ObjCClassSwizzlerTestOne> object_one(
127 [[ObjCClassSwizzlerTestOne alloc] init]);
128 EXPECT_EQ(3, [object_one method]);
129
130 {
131 base::mac::ScopedObjCClassSwizzler swizzler(
132 [ObjCClassSwizzlerTestOne class],
133 @selector(method),
134 @selector(alternate));
135 EXPECT_EQ(9, [object_one method]);
136
137 IMP original = swizzler.GetOriginalImplementation();
138 id expected_result = reinterpret_cast<id>(3);
139 EXPECT_EQ(expected_result, original(object_one, @selector(method)));
140 }
141
142 EXPECT_EQ(3, [object_one method]);
143}
144
145TEST(ObjCClassSwizzlerTest, SwizzleViaInheritance) {
146 base::scoped_nsobject<ObjCClassSwizzlerTestOneChild> child(
147 [[ObjCClassSwizzlerTestOneChild alloc] init]);
148 EXPECT_EQ(3, [child method]);
149
150 {
151 base::mac::ScopedObjCClassSwizzler swizzler(
152 [ObjCClassSwizzlerTestOneChild class],
153 @selector(method),
154 @selector(childAlternate));
155 EXPECT_EQ(15, [child method]);
156
157 IMP original = swizzler.GetOriginalImplementation();
158 id expected_result = reinterpret_cast<id>(3);
159 EXPECT_EQ(expected_result, original(child, @selector(method)));
160 }
161
162 EXPECT_EQ(3, [child method]);
163}
164
165} // namespace mac
166} // namespace base