{"action":"created","issue":{"url":"https://api.github.com/repos/meekrosoft/fff/issues/14","repository_url":"https://api.github.com/repos/meekrosoft/fff","labels_url":"https://api.github.com/repos/meekrosoft/fff/issues/14/labels{/name}","comments_url":"https://api.github.com/repos/meekrosoft/fff/issues/14/comments","events_url":"https://api.github.com/repos/meekrosoft/fff/issues/14/events","html_url":"https://github.com/meekrosoft/fff/issues/14","id":162965518,"number":14,"title":"Support for creating testing seams","user":{"login":"frankbenoit","id":8962790,"avatar_url":"https://avatars.githubusercontent.com/u/8962790?v=3","gravatar_id":"","url":"https://api.github.com/users/frankbenoit","html_url":"https://github.com/frankbenoit","followers_url":"https://api.github.com/users/frankbenoit/followers","following_url":"https://api.github.com/users/frankbenoit/following{/other_user}","gists_url":"https://api.github.com/users/frankbenoit/gists{/gist_id}","starred_url":"https://api.github.com/users/frankbenoit/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/frankbenoit/subscriptions","organizations_url":"https://api.github.com/users/frankbenoit/orgs","repos_url":"https://api.github.com/users/frankbenoit/repos","events_url":"https://api.github.com/users/frankbenoit/events{/privacy}","received_events_url":"https://api.github.com/users/frankbenoit/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"assignees":[],"milestone":null,"comments":6,"created_at":"2016-06-29T16:07:17Z","updated_at":"2017-02-06T20:10:09Z","closed_at":null,"body":"Hi\n\ni would like to have `fff` to support the dynamic exchange of the functions.\n\nLets say i have a function `foo+bar` and i want to replacy it with my fakes called `fooTest+barTest`. Then i would like to have expanded code like this:\n\nIn case for working with unittesting, i set the #define UNIT_TESTING  \nheader:\n\n```\nextern void (*foo_TestPtr)( int a );\nvoid foo( int a );\nextern int (*bar_TestPtr)( int a );\nint bar( int a );\n```\n\nsource:\n\n```\nvoid (*foo_TestPtr)( int a ) = NULL;\nvoid foo( int a ){\n    if( foo_TestPtr ){\n        foo_TestPtr( a );\n        return;\n    }\n    // ... implementation\n}\n\nint (*bar_TestPtr)( int a ) = NULL;\nint bar( int a ){\n    if( bar_TestPtr ){\n        return bar_TestPtr( a );\n    }\n    // ... implementation\n}\n```\n\nWhen #define UNIT_TESTING is not set, this expands to:\n\nheader:\n\n```\nvoid foo( int a );\nint bar( int a );\n```\n\nsource:\n\n```\nvoid foo( int a ){\n    // ... implementation\n}\n\nint bar( int a ){\n    // ... implementation\n}\n```\n\nAnd this is, how i want to write it:\n\nheader:\n\n```\nFUNC_DECL( void, foo,( int a ));\nFUNC_DECL( int, bar,( int a ));\n```\n\nsource:\n\n```\nFUNC_IMPL( void, foo,( int a )){\n    FUNC_VOID_REDIR( foo, (a))\n\n    // ... implementation\n}\n\nFUNC_IMPL( int, bar,( int a )){\n    FUNC_VALUE_REDIR( bar, (a))\n    // ... implementation\n}\n```\n\nTo implement, this can look like this:\n\n```\n#ifdef UNIT_TESTING\n/**\n * Declare a function normally and a function pointer with _TestPtr postfix.\n *\n * Example:\n *   int example( char* name );\n *\n * Use of the macro:\n *   FUNC_DECL(int, example, ( char* name ));\n *\n * Expands to:\n *   int example( char* name );\n *   int (*example_TestPtr)( char* name );\n */\n# define FUNC_DECL(r,n,a) \\\n        r n a;\\\n        extern r (*n##_TestPtr) a\n#else\n# define FUNC_DECL(r,n,a) extern r n a\n#endif\n\n#ifdef UNIT_TESTING\n/**\n * Define the function pointer and the function signature\n *\n * Example:\n *   int example( char* name ){ ...\n *\n * Use of the macro:\n *   FUNC_IMPL(int, example, ( char* name )) { ...\n *\n * Expands to:\n *   int (*example_TestPtr)( char* name ) = NULL;\n *   int example( char* name ) { ...\n *\n *\n */\n# define FUNC_IMPL(r,n,a) \\\n    r (*n##_TestPtr) a = NULL;\\\n    r n a\n#else\n# define FUNC_IMPL(r,n,a) r n a\n#endif\n\n#ifdef UNIT_TESTING\n/**\n * Function redirect for functions without return value.\n *\n * FUNC_IMPL(void, example, ( char* name )) {\n *      FUNC_REDIR_VOID( example, name )\n *      ...\n * }\n *\n * Expands to:\n *   void (*example_TestPtr)( char* name ) = NULL;\n *   void example( char* name ) {\n *       if( example_TestPtr ){\n *           return example_TestPtr( name );\n *       }\n */\n# define FUNC_REDIR_VOID(n,a) \\\n    do{ if( n##_TestPtr ){\\\n        n##_TestPtr a;\\\n        return;\\\n    } } while( false )\n#else\n# define FUNC_REDIR_VOID(n,a) \\\n    do{ } while( false )\n#endif\n\n#ifdef UNIT_TESTING\n/**\n * Function redirect for function with return value.\n *\n * FUNC_IMPL(int, example, ( char* name )) {\n *      FUNC_REDIR_VALUE( example, name )\n *      ...\n * }\n *\n * Expands to:\n *   int (*example_TestPtr)( char* name ) = NULL;\n *   int example( char* name ) {\n *       if( example_TestPtr ){\n *           example_TestPtr( name );\n *           return;\n *       }\n */\n# define FUNC_REDIR_VALUE(n,a) \\\n    do{ if( n##_TestPtr ){\\\n        return n##_TestPtr a;\\\n    }} while( false )\n#else\n# define FUNC_REDIR_VALUE(n,a) \\\n    do{ } while( false )\n#endif\n```\n\nThis way, you have function runtime substitution, like you discussed here: \nhttps://meekrosoft.wordpress.com/2012/07/20/test-seams-in-c-function-pointers-vs-preprocessor-hash-defines-vs-link-time-substitution/\nBut the two contra arguments are removed. Now the IDE can resolve the function calls, do auto completion and do code analysis.\n\nFinally, if there would be a way to make the FUNC_IMPL and FUNC_VOID_REDIR a single macro call, this would be super cool. But I don't know how to do that. Perhaps you?\n\nFrank\n"},"comment":{"url":"https://api.github.com/repos/meekrosoft/fff/issues/comments/277798425","html_url":"https://github.com/meekrosoft/fff/issues/14#issuecomment-277798425","issue_url":"https://api.github.com/repos/meekrosoft/fff/issues/14","id":277798425,"user":{"login":"usr42","id":6493840,"avatar_url":"https://avatars.githubusercontent.com/u/6493840?v=3","gravatar_id":"","url":"https://api.github.com/users/usr42","html_url":"https://github.com/usr42","followers_url":"https://api.github.com/users/usr42/followers","following_url":"https://api.github.com/users/usr42/following{/other_user}","gists_url":"https://api.github.com/users/usr42/gists{/gist_id}","starred_url":"https://api.github.com/users/usr42/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/usr42/subscriptions","organizations_url":"https://api.github.com/users/usr42/orgs","repos_url":"https://api.github.com/users/usr42/repos","events_url":"https://api.github.com/users/usr42/events{/privacy}","received_events_url":"https://api.github.com/users/usr42/received_events","type":"User","site_admin":false},"created_at":"2017-02-06T20:10:08Z","updated_at":"2017-02-06T20:10:08Z","body":"@espenalb Have you already tested the `--wrap` approach?\r\n@frankbenoit Is the `--wrap` approach working for your purpose?"}}
{"actor":{"display_login":"usr42"}}