-
Notifications
You must be signed in to change notification settings - Fork 0
/
component---src-docs-cpp-stubs-md-9672adf8e1c77a7d3da2.js
2 lines (2 loc) · 10.2 KB
/
component---src-docs-cpp-stubs-md-9672adf8e1c77a7d3da2.js
1
2
"use strict";(self.webpackChunkunittestbot_web=self.webpackChunkunittestbot_web||[]).push([[356],{50432:function(e,n,t){t.r(n),t.d(n,{_frontmatter:function(){return r},default:function(){return d}});var i=t(87462),o=t(63366),a=(t(15007),t(64983)),s=t(23017),l=(t(13879),["components"]),r={};void 0!==r&&r&&r===Object(r)&&Object.isExtensible(r)&&!Object.prototype.hasOwnProperty.call(r,"__filemeta")&&Object.defineProperty(r,"__filemeta",{configurable:!0,value:{name:"_frontmatter",filename:"src/docs/cpp/stubs.md"}});var u={_frontmatter:r},c=s.Z;function d(e){var n=e.components,t=(0,o.Z)(e,l);return(0,a.kt)(c,(0,i.Z)({},u,t,{components:n,mdxType:"MDXLayout"}),(0,a.kt)("h1",{id:"stubs"},"Stubs"),(0,a.kt)("p",null,"Here we describe how stubs are generated and what they are needed for."),(0,a.kt)("blockquote",null,(0,a.kt)("p",{parentName:"blockquote"},"📝",(0,a.kt)("strong",{parentName:"p"},"Note")),(0,a.kt)("p",{parentName:"blockquote"},(0,a.kt)("strong",{parentName:"p"},"Stub")," is a function which emulates behavior of another function it is written for.\nIt's often useful to write stubs for functions from another module that you don't want to test.")),(0,a.kt)("h3",{id:"when-stubs-are-used"},"When stubs are used"),(0,a.kt)("p",null,"UTBot generates stubs for every function in the project first time you open it and synchronize each time before test\ngeneration."),(0,a.kt)("p",null,"First time you open the project you will see ",(0,a.kt)("inlineCode",{parentName:"p"},"UTBot is generating stubs for project...")," message. It means that for each\nfile in your project UTBot generates file which contains all non-static functions signatures from the source file. Stubs\ncan be used as substitutes for calling functions from another module. Consider the following project structure:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},"executable\n|---- lib1.a\n| |---- A.c\n| +---- B.c\n|---- lib2.a\n| |---- C.c\n")),(0,a.kt)("p",null,"If we run test generation for ",(0,a.kt)("inlineCode",{parentName:"p"},"C.c"),", all functions from ",(0,a.kt)("inlineCode",{parentName:"p"},"lib1.a")," will be replaced with their stubs on build step. So, if\nthe function ",(0,a.kt)("inlineCode",{parentName:"p"},"foo")," from ",(0,a.kt)("inlineCode",{parentName:"p"},"C.c")," calls the function ",(0,a.kt)("inlineCode",{parentName:"p"},"bar")," from ",(0,a.kt)("inlineCode",{parentName:"p"},"A.c"),", then stub for the function ",(0,a.kt)("inlineCode",{parentName:"p"},"bar")," will be invoked\ninstead. Note that you can still generate tests using the exact definition of ",(0,a.kt)("inlineCode",{parentName:"p"},"bar"),"; for that, you will need to\nunmark ",(0,a.kt)("inlineCode",{parentName:"p"},"Use Stubs")," checkbox in ",(0,a.kt)("a",{parentName:"p",href:"vscode-extension-settings#use-stubs"},"settings"),"."),(0,a.kt)("h3",{id:"stub-file-example"},"Stub file example"),(0,a.kt)("p",null,"Stub files can be found in ",(0,a.kt)("inlineCode",{parentName:"p"},"tests/stubs")," folder. This is an example of stub file generated\nfor ",(0,a.kt)("inlineCode",{parentName:"p"},"c-example/lib/dependent_functions.c")," from\nthe ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/UnitTestBot/UTBotCpp/tree/main/integration-tests/c-example"},"example project"),":"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-cpp"},'// 1624618650000000000\n// Please, do not change the line above\n\n#ifdef\nKLEE_MODE\nextern void klee_make_symbolic(void *addr, unsigned long long nbytes, const char *name);\n#endif\n#include\n"dependent_functions_stub.h"\n\n#define\nNULL ((void*)0)\n\nint double_max_symbolic;\nint double_max(int a, int b) {\nstatic int firstTimeCall = 1;\n#ifdef\nKLEE_MODE\nif (firstTimeCall == 1) {\nfirstTimeCall = 0;\nklee_make_symbolic(&double_max_symbolic, sizeof(double_max_symbolic), "double_max_symbolic");\n}\n#endif\nreturn double_max_symbolic;\n}\n\n')),(0,a.kt)("p",null,"The first line contains timestamp of stub file creation. It is required for synchronization with the source code, so,\nplease, do not modify this line:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-cpp"},"// 1619438023000000000\n")),(0,a.kt)("p",null,"Then, if a ",(0,a.kt)("inlineCode",{parentName:"p"},"KLEE_MODE")," macro is passed during preprocessing, we add a KLEE declaration to allow us to use symbolic\nreturn value. ",(0,a.kt)("inlineCode",{parentName:"p"},"KLEE_MODE")," serves for both test generation and test running purposes."),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-cpp"},"#ifdef KLEE_MODE\nextern void klee_make_symbolic(void *addr, unsigned long long nbytes, const char *name);\n#endif\n")),(0,a.kt)("p",null,"This variable stores return value of the stub function:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-cpp"},"int double_max_symbolic;\n")),(0,a.kt)("p",null,"Stub function signature is always the same as the signature of the source function. If it's not (for example, if the\nfunction was modified), then UTBot will synchronize them by rewriting stub function with the new one:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-cpp"},"int double_max(int a, int b)\n")),(0,a.kt)("p",null,"If UTBot uses stubs, then ",(0,a.kt)("inlineCode",{parentName:"p"},"KLEE_MODE")," is defined, and the return value is made symbolic. This way KLEE can decide what\nvalues to return to satisfy the execution paths:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-cpp"},'static int firstTimeCall = 1;\n#ifdef KLEE_MODE\n if (firstTimeCall == 1) {\n firstTimeCall = 0;\n klee_make_symbolic(&double_max_symbolic, sizeof(double_max_symbolic), "double_max_symbolic");\n }\n#endif\n')),(0,a.kt)("h3",{id:"stub-headers"},"Stub headers"),(0,a.kt)("p",null,"For each stub, a header is generated. It contains definitions of types and structures used in function headers, allowing\nstubs to be compilable. Stub headers may contain definitions fetched from system headers and may look obscure, but\nusually you will not modify them."),(0,a.kt)("blockquote",null,(0,a.kt)("p",{parentName:"blockquote"},"📝",(0,a.kt)("strong",{parentName:"p"},"Note")),(0,a.kt)("p",{parentName:"blockquote"},"You can change the stub function body however you want. UTBot saves custom code inside the function while synchronizing. However, if the source function signature changes, then stub function will be completely rewritten.")),(0,a.kt)("h3",{id:"tests-with-stubs"},"Tests with stubs"),(0,a.kt)("p",null,"For the tests that use stubs, the return values are generated in a such way that the code coverage is maximized. For\nexample:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-cpp"},"extern \"C\" char pointerToPointer_symbolic;\n\nTEST(regression, calc_two_numbers_f_test_1)\n{\n // Initialize symbolic stubs\n pointerToPointer_symbolic = '\\x10';\n\n // Construct input\n char a = 'c';\n char b = 'p';\n\n // Expected output\n int expected = 2;\n\n // Trigger the function\n int actual = calc_two_numbers_f(a, b);\n\n // Check results\n EXPECT_EQ(expected, actual);\n}\n\nTEST(regression, calc_two_numbers_f_test_2)\n{\n // Initialize symbolic stubs\n pointerToPointer_symbolic = 'b';\n\n // Construct input\n char a = 'c';\n char b = 'b';\n\n // Expected output\n int expected = 1;\n\n // Trigger the function\n int actual = calc_two_numbers_f(a, b);\n\n // Check results\n EXPECT_EQ(expected, actual);\n}\n")),(0,a.kt)("p",null,"Here ",(0,a.kt)("inlineCode",{parentName:"p"},"pointerToPointer_symbolic")," stores return value for ",(0,a.kt)("inlineCode",{parentName:"p"},"pointerToPointer")," stub function."),(0,a.kt)("h3",{id:"modifying-stubs"},"Modifying stubs"),(0,a.kt)("p",null,"As it was noted, it is easy to rewrite UTBot stubs into anything you want them to be. You should modify only function\nbodies and not touch header include, or ",(0,a.kt)("inlineCode",{parentName:"p"},"KLEE_MODE")," ifdefs. Consider the simplest example:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-cpp"},'// 1624618650000000000\n// Please, do not change the line above\n\n#ifdef\nKLEE_MODE\nextern void klee_make_symbolic(void *addr, unsigned long long nbytes, const char *name);\n#endif\n#include\n"dependent_functions_stub.h"\n\n#define\nNULL ((void*)0)\n\nint double_max_symbolic;\nint double_max(int a, int b) {\nreturn a;\n}\n')),(0,a.kt)("p",null,"In such a case, UTBot will generate tests for functions from other CMake modules implying\nthat ",(0,a.kt)("inlineCode",{parentName:"p"},"double_max(int a, int b) = a"),"."),(0,a.kt)("p",null,"However, you can also use symbolic variable power when modifying stubs. Suppose that you want your function not to\nreturn any value, but perform some checks on the arguments prior to that. Also, there may be a special case in that\nfunction that is highly important to be reflected in the stub. In that case, you can insert those checks in the stub,\nand, if they succeed, return a symbolic value:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-cpp"},'// 1624618650000000000\n// Please, do not change the line above\n\n#ifdef\nKLEE_MODE\nextern void klee_make_symbolic(void *addr, unsigned long long nbytes, const char *name);\n#endif\n#include\n"dependent_functions_stub.h"\n\n#define\nNULL ((void*)0)\n\nint double_max_symbolic;\nint double_max(int a, int b) {\nif (a == 100 && a > b) {\nreturn 100;\n}\nstatic int firstTimeCall = 1;\n#ifdef\nKLEE_MODE\nif (firstTimeCall == 1) {\nfirstTimeCall = 0;\nklee_make_symbolic(&double_max_symbolic, sizeof(double_max_symbolic), "double_max_symbolic");\n}\n#endif\nreturn double_max_symbolic;\n}\n')),(0,a.kt)("p",null,"By this change, ",(0,a.kt)("inlineCode",{parentName:"p"},"double_max(a, b)")," will preserve its behaviour if a certain condition holds. This principle can be used\nto achieve the similarity of the stub and the original code while leaving out big parts of code."))}d&&d===Object(d)&&Object.isExtensible(d)&&!Object.prototype.hasOwnProperty.call(d,"__filemeta")&&Object.defineProperty(d,"__filemeta",{configurable:!0,value:{name:"MDXContent",filename:"src/docs/cpp/stubs.md"}}),d.isMDXComponent=!0}}]);
//# sourceMappingURL=component---src-docs-cpp-stubs-md-9672adf8e1c77a7d3da2.js.map