auto_testing_hook.h revision 5821806d5e7f356e8fa4b058a389a808ea183019
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 41namespace sidestep { 42 43// Same trick as common/scope_cleanup.h ScopeGuardImplBase 44class 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. 57typedef 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)) {} 65class 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. 85template <typename T> 86class 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 135template <typename T> 136inline AutoTestingHookImpl<T> MakeTestingHook(T target, 137 T replacement, 138 bool do_it) { 139 return AutoTestingHookImpl<T>::MakeTestingHook(target, replacement, do_it); 140} 141 142template <typename T> 143inline AutoTestingHookImpl<T> MakeTestingHook(T target, T replacement) { 144 return AutoTestingHookImpl<T>::MakeTestingHook(target, replacement, true); 145} 146 147template <typename T> 148inline 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_ 156