OLD | NEW |
| (Empty) |
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | |
2 // | |
3 // Redistribution and use in source and binary forms, with or without | |
4 // modification, are permitted provided that the following conditions are | |
5 // met: | |
6 // | |
7 // * Redistributions of source code must retain the above copyright | |
8 // notice, this list of conditions and the following disclaimer. | |
9 // * Redistributions in binary form must reproduce the above | |
10 // copyright notice, this list of conditions and the following disclaimer | |
11 // in the documentation and/or other materials provided with the | |
12 // distribution. | |
13 // * Neither the name of Google Inc. nor the names of its | |
14 // contributors may be used to endorse or promote products derived from | |
15 // this software without specific prior written permission. | |
16 // | |
17 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
18 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
19 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
20 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
21 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
22 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
23 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
24 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
25 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
26 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
27 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
28 // | |
29 // Utility for using SideStep with unit tests. | |
30 | |
31 #ifndef CEEE_TESTING_SIDESTEP_AUTO_TESTING_HOOK_H_ | |
32 #define CEEE_TESTING_SIDESTEP_AUTO_TESTING_HOOK_H_ | |
33 | |
34 #include "base/basictypes.h" | |
35 #include "base/logging.h" | |
36 #include "preamble_patcher.h" | |
37 | |
38 #define SIDESTEP_CHK(x) CHECK(x) | |
39 #define SIDESTEP_EXPECT_TRUE(x) SIDESTEP_CHK(x) | |
40 | |
41 namespace sidestep { | |
42 | |
43 // Same trick as common/scope_cleanup.h ScopeGuardImplBase | |
44 class AutoTestingHookBase { | |
45 public: | |
46 virtual ~AutoTestingHookBase() {} | |
47 }; | |
48 | |
49 // This is the typedef you normally use for the class, e.g. | |
50 // | |
51 // AutoTestingHook hook = MakeTestingHook(TargetFunc, HookTargetFunc); | |
52 // | |
53 // The 'hook' variable will then be destroyed when it goes out of scope. | |
54 // | |
55 // NOTE: You must not hold this type as a member of another class. Its | |
56 // destructor will not get called. | |
57 typedef const AutoTestingHookBase& AutoTestingHook; | |
58 | |
59 // This is the class you must use when holding a hook as a member of another | |
60 // class, e.g. | |
61 // | |
62 // public: | |
63 // AutoTestingHookHolder holder_; | |
64 // MyClass() : my_hook_holder(MakeTestingHookHolder(Target, Hook)) {} | |
65 class AutoTestingHookHolder { | |
66 public: | |
67 explicit AutoTestingHookHolder(AutoTestingHookBase* hook) : hook_(hook) {} | |
68 ~AutoTestingHookHolder() { delete hook_; } | |
69 private: | |
70 AutoTestingHookHolder() {} // disallow | |
71 AutoTestingHookBase* hook_; | |
72 }; | |
73 | |
74 // This class helps patch a function, then unpatch it when the object exits | |
75 // scope, and also maintains the pointer to the original function stub. | |
76 // | |
77 // To enable use of the class without having to explicitly provide the | |
78 // type of the function pointers (and instead only providing it | |
79 // implicitly) we use the same trick as ScopeGuard (see | |
80 // common/scope_cleanup.h) uses, so to create a hook you use the MakeHook | |
81 // function rather than a constructor. | |
82 // | |
83 // NOTE: This function is only safe for e.g. unit tests and _not_ for | |
84 // production code. See PreamblePatcher class for details. | |
85 template <typename T> | |
86 class AutoTestingHookImpl : public AutoTestingHookBase { | |
87 public: | |
88 static AutoTestingHookImpl<T> MakeTestingHook(T target_function, | |
89 T replacement_function, | |
90 bool do_it) { | |
91 return AutoTestingHookImpl<T>(target_function, replacement_function, do_it); | |
92 } | |
93 | |
94 static AutoTestingHookImpl<T>* MakeTestingHookHolder(T target_function, | |
95 T replacement_function, | |
96 bool do_it) { | |
97 return new AutoTestingHookImpl<T>(target_function, | |
98 replacement_function, do_it); | |
99 } | |
100 | |
101 ~AutoTestingHookImpl() { | |
102 if (did_it_) { | |
103 SIDESTEP_CHK(SIDESTEP_SUCCESS == PreamblePatcher::Unpatch( | |
104 (void*)target_function_, (void*)replacement_function_, | |
105 (void*)original_function_)); | |
106 } | |
107 } | |
108 | |
109 // Returns a pointer to the original function. To use this method you will | |
110 // have to explicitly create an AutoTestingHookImpl of the specific | |
111 // function pointer type (i.e. not use the AutoTestingHook typedef). | |
112 T original_function() { | |
113 return original_function_; | |
114 } | |
115 | |
116 private: | |
117 AutoTestingHookImpl(T target_function, T replacement_function, bool do_it) | |
118 : target_function_(target_function), | |
119 original_function_(NULL), | |
120 replacement_function_(replacement_function), | |
121 did_it_(do_it) { | |
122 if (do_it) { | |
123 SIDESTEP_CHK(SIDESTEP_SUCCESS == PreamblePatcher::Patch(target_function, | |
124 replacement_function, | |
125 &original_function_)); | |
126 } | |
127 } | |
128 | |
129 T target_function_; // always valid | |
130 T original_function_; // always valid | |
131 T replacement_function_; // always valid | |
132 bool did_it_; // Remember if we did it or not... | |
133 }; | |
134 | |
135 template <typename T> | |
136 inline AutoTestingHookImpl<T> MakeTestingHook(T target, | |
137 T replacement, | |
138 bool do_it) { | |
139 return AutoTestingHookImpl<T>::MakeTestingHook(target, replacement, do_it); | |
140 } | |
141 | |
142 template <typename T> | |
143 inline AutoTestingHookImpl<T> MakeTestingHook(T target, T replacement) { | |
144 return AutoTestingHookImpl<T>::MakeTestingHook(target, replacement, true); | |
145 } | |
146 | |
147 template <typename T> | |
148 inline AutoTestingHookImpl<T>* MakeTestingHookHolder(T target, T replacement) { | |
149 return AutoTestingHookImpl<T>::MakeTestingHookHolder(target, replacement, | |
150 true); | |
151 } | |
152 | |
153 }; // namespace sidestep | |
154 | |
155 #endif // CEEE_TESTING_SIDESTEP_AUTO_TESTING_HOOK_H_ | |
OLD | NEW |