Blame include/psm2_mock_testing.h

Packit 961e70
/*
Packit 961e70
Packit 961e70
  This file is provided under a dual BSD/GPLv2 license.  When using or
Packit 961e70
  redistributing this file, you may do so under either license.
Packit 961e70
Packit 961e70
  GPL LICENSE SUMMARY
Packit 961e70
Packit 961e70
  Copyright(c) 2016 Intel Corporation.
Packit 961e70
Packit 961e70
  This program is free software; you can redistribute it and/or modify
Packit 961e70
  it under the terms of version 2 of the GNU General Public License as
Packit 961e70
  published by the Free Software Foundation.
Packit 961e70
Packit 961e70
  This program is distributed in the hope that it will be useful, but
Packit 961e70
  WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 961e70
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 961e70
  General Public License for more details.
Packit 961e70
Packit 961e70
  Contact Information:
Packit 961e70
  Intel Corporation, www.intel.com
Packit 961e70
Packit 961e70
  BSD LICENSE
Packit 961e70
Packit 961e70
  Copyright(c) 2016 Intel Corporation.
Packit 961e70
Packit 961e70
  Redistribution and use in source and binary forms, with or without
Packit 961e70
  modification, are permitted provided that the following conditions
Packit 961e70
  are met:
Packit 961e70
Packit 961e70
    * Redistributions of source code must retain the above copyright
Packit 961e70
      notice, this list of conditions and the following disclaimer.
Packit 961e70
    * Redistributions in binary form must reproduce the above copyright
Packit 961e70
      notice, this list of conditions and the following disclaimer in
Packit 961e70
      the documentation and/or other materials provided with the
Packit 961e70
      distribution.
Packit 961e70
    * Neither the name of Intel Corporation nor the names of its
Packit 961e70
      contributors may be used to endorse or promote products derived
Packit 961e70
      from this software without specific prior written permission.
Packit 961e70
Packit 961e70
  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
Packit 961e70
  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
Packit 961e70
  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
Packit 961e70
  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
Packit 961e70
  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
Packit 961e70
  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
Packit 961e70
  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
Packit 961e70
  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
Packit 961e70
  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
Packit 961e70
  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
Packit 961e70
  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Packit 961e70
Packit 961e70
*/
Packit 961e70
Packit 961e70
#ifndef PSM2_MOCK_TESTING_H
Packit 961e70
#define PSM2_MOCK_TESTING_H
Packit 961e70
Packit 961e70
/* PSM2_MOCK_TESTING being defined flips a couple of switches so that a
Packit 961e70
 * testable version of libpsm2.so is built. It'll make properly annotated
Packit 961e70
 * static functions be non-static, visible to the outside. Also, all mockable
Packit 961e70
 * functions will be replaced with function pointers which will originally
Packit 961e70
 * point to the actual implementation. However, those function pointers might
Packit 961e70
 * be reset by the test code, thus allowing for mocking selected PSM2 functions
Packit 961e70
 * for the purpose of the test.
Packit 961e70
 *
Packit 961e70
 * So far the following utilities have been introduced for enabling a
Packit 961e70
 * conditional compilation of the testable vs. production version of the library:
Packit 961e70
 *  - ustatic: toggles function visibility
Packit 961e70
 *  - MOCKABLE(): decorates function name so that it is visible after being mocked
Packit 961e70
 *  - MOCK_DCL_EPILOGUE(): declares a function pointer which will be the seam
Packit 961e70
 *        for mocking a function
Packit 961e70
 *  - MOCK_DEF_EPILOGUE(): defines a function pointer which will be the seam
Packit 961e70
 *        for mocking a function
Packit 961e70
 *
Packit 961e70
 * If the declaration and definition of a static function @c foo reside in
Packit 961e70
 * different files, this would be the common use case:
Packit 961e70
 *
Packit 961e70
 * @code
Packit 961e70
 * // somefile.c:
Packit 961e70
 * int MOCKABLE(foo)();
Packit 961e70
 * MOCK_DCL_EPILOGUE(foo);
Packit 961e70
 *
Packit 961e70
 * // otherfile.c:
Packit 961e70
 * int MOCKABLE(foo)() {
Packit 961e70
 * 	printf("I am the original foo!\n");
Packit 961e70
 * }
Packit 961e70
 * MOCK_DEF_EPILOGUE(foo);
Packit 961e70
 * @endcode
Packit 961e70
 *
Packit 961e70
 * If the production version of the library is being built, the following code
Packit 961e70
 * would result:
Packit 961e70
 * @code
Packit 961e70
 * // somefile.c:
Packit 961e70
 * int foo();
Packit 961e70
 *
Packit 961e70
 * // otherfile.c:
Packit 961e70
 * int foo() {
Packit 961e70
 * 	printf("I am the original foo!\n");
Packit 961e70
 * }
Packit 961e70
 * @endcode
Packit 961e70
 *
Packit 961e70
 * On the other hand, if a testable version of the libary is being build, it
Packit 961e70
 * would produce the following code:
Packit 961e70
 * @code
Packit 961e70
 * // somefile.c:
Packit 961e70
 * int foo_original_();
Packit 961e70
 * extern typeof(& foo_original_) foo;
Packit 961e70
 *
Packit 961e70
 * // otherfile.c:
Packit 961e70
 * int foo_original_() {
Packit 961e70
 * 	printf("I am the original foo!\n");
Packit 961e70
 * }
Packit 961e70
 * typeof(& foo_original_) foo = foo_original_;
Packit 961e70
 * @endcode
Packit 961e70
 *
Packit 961e70
 * If the function to be mocked is a static function residing in the header,
Packit 961e70
 * the following syntax would be used:
Packit 961e70
 * @code
Packit 961e70
 * // somefile.c:
Packit 961e70
 * ustatic int MOCKABLE(foo)() {
Packit 961e70
 * 	printf("I am the original foo!\n");
Packit 961e70
 * }
Packit 961e70
 * MOCK_DCL_EPILOGUE(foo);
Packit 961e70
 * MOCK_DEF_EPILOGUE(foo);
Packit 961e70
 * @endcode
Packit 961e70
 *
Packit 961e70
 * If the production version of the library is being built, the following code
Packit 961e70
 * would result:
Packit 961e70
 * @code
Packit 961e70
 * // somefile.c:
Packit 961e70
 * static int foo() {
Packit 961e70
 * 	printf("I am the original foo!\n");
Packit 961e70
 * }
Packit 961e70
 * @endcode
Packit 961e70
 *
Packit 961e70
 * Similarly, if a testable version of the libary is being build, it would
Packit 961e70
 * produce the following code:
Packit 961e70
 * @code
Packit 961e70
 * // somefile.c:
Packit 961e70
 * int foo_original_();
Packit 961e70
 * extern typeof(& foo_original_) foo;
Packit 961e70
 * typeof(& foo_original_) foo = foo_original_;
Packit 961e70
 * @endcode
Packit 961e70
 */
Packit 961e70
#ifndef PSM2_MOCK_TESTING
Packit 961e70
Packit 961e70
/* If no testing is being done, ustatic resolves to regular "static" */
Packit 961e70
#define ustatic static
Packit 961e70
/* If no testing is being done, no indirection is introduced */
Packit 961e70
#define MOCKABLE(fname) fname
Packit 961e70
/* If no testing is being done, no declaration epilogue is needed */
Packit 961e70
#define MOCK_DCL_EPILOGUE(fname)
Packit 961e70
/* If no testing is being done, no definition epilogue is needed */
Packit 961e70
#define MOCK_DEF_EPILOGUE(fname)
Packit 961e70
Packit 961e70
#else /* ndef PSM2_MOCK_TESTING */
Packit 961e70
Packit 961e70
/* For the testable version, all _ustatic_ function will NOT be static */
Packit 961e70
#define ustatic
Packit 961e70
/* TODO override inline directives in the same fashion as static */
Packit 961e70
/* For the testable version, the actual implementation function is renamed */
Packit 961e70
#define MOCKABLE(x) x ## _original_
Packit 961e70
/* For the testable version, we declare the function pointer which will be the
Packit 961e70
 * point of indirection for calls to that function. It must be delared after
Packit 961e70
 * the declaration of the actual function happens.
Packit 961e70
 */
Packit 961e70
#define MOCK_DCL_EPILOGUE(x) extern typeof(& x ## _original_) x;
Packit 961e70
/* For the testable version, we define the function pointer which will be the
Packit 961e70
 * point of indirection for calls to that function. It must be delared after
Packit 961e70
 * the definition of the actual function happens.
Packit 961e70
 */
Packit 961e70
#define MOCK_DEF_EPILOGUE(x) typeof(& x ## _original_) x = x ## _original_;
Packit 961e70
Packit 961e70
#endif /* ndef PSM2_MOCK_TESTING */
Packit 961e70
Packit 961e70
#endif /* PSM2_MOCK_TESTING_H */
Packit 961e70