|
| 1 | +********************** |
| 2 | +:toolname:`GNATstub` |
| 3 | +********************** |
| 4 | + |
| 5 | +.. container:: PRELUDE BEGIN |
| 6 | + |
| 7 | +.. container:: PRELUDE ROLES |
| 8 | + |
| 9 | +.. role:: ada(code) |
| 10 | + :language: Ada |
| 11 | + |
| 12 | +.. role:: C(code) |
| 13 | + :language: C |
| 14 | + |
| 15 | +.. role:: cpp(code) |
| 16 | + :language: C++ |
| 17 | + |
| 18 | +.. role:: rust(code) |
| 19 | + :language: Rust |
| 20 | + |
| 21 | +.. container:: PRELUDE SYMBOLS |
| 22 | + |
| 23 | +.. |rightarrow| replace:: :math:`\rightarrow` |
| 24 | +.. |forall| replace:: :math:`\forall` |
| 25 | +.. |exists| replace:: :math:`\exists` |
| 26 | +.. |equivalent| replace:: :math:`\iff` |
| 27 | +.. |le| replace:: :math:`\le` |
| 28 | +.. |ge| replace:: :math:`\ge` |
| 29 | +.. |lt| replace:: :math:`<` |
| 30 | +.. |gt| replace:: :math:`>` |
| 31 | +.. |checkmark| replace:: :math:`\checkmark` |
| 32 | + |
| 33 | +.. container:: PRELUDE REQUIRES |
| 34 | + |
| 35 | +.. container:: PRELUDE PROVIDES |
| 36 | + |
| 37 | +.. container:: PRELUDE END |
| 38 | + |
| 39 | +============== |
| 40 | +Introduction |
| 41 | +============== |
| 42 | + |
| 43 | +--------------------- |
| 44 | +Body Stub Generator |
| 45 | +--------------------- |
| 46 | + |
| 47 | +* Creates empty (but compilable) package/subprogram bodies |
| 48 | +* Can use GNAT Project file |
| 49 | + |
| 50 | + * Configuration in package :ada:`gnatstub` |
| 51 | + |
| 52 | +* Default behavior is to raise exception if stub is called |
| 53 | + |
| 54 | + * It means you did not create a "real" body |
| 55 | + |
| 56 | +------------------------ |
| 57 | +Why Do You Need Stubs? |
| 58 | +------------------------ |
| 59 | + |
| 60 | +Sometimes we want to establish code structure quickly |
| 61 | + |
| 62 | + * Start prototyping code architecture first |
| 63 | + * Worry about implementation details later |
| 64 | + |
| 65 | + * Don't want to get caught in compilation details/behavior in early development |
| 66 | + |
| 67 | +============================== |
| 68 | +Running :toolname:`GNATstub` |
| 69 | +============================== |
| 70 | + |
| 71 | +------------------------------ |
| 72 | +Running :toolname:`GNATstub` |
| 73 | +------------------------------ |
| 74 | + |
| 75 | +:command:`gnatstub [switches] {filename}` |
| 76 | + |
| 77 | +where :filename:`{filename}` can be a package spec or body |
| 78 | + |
| 79 | +* Package spec |
| 80 | + |
| 81 | + * :toolname:`GNATstub` will generate a package body containing "dummy" bodies for subprograms defined not completed in the spec |
| 82 | + |
| 83 | +* Package body |
| 84 | + |
| 85 | + * For any subprogram defined as :ada:`separate` in the package body, a file will be created containing a body for the subprogram |
| 86 | + |
| 87 | +.. note:: Need to specify :command:`--subunits` switch |
| 88 | + |
| 89 | +---------------------- |
| 90 | +Example Package Spec |
| 91 | +---------------------- |
| 92 | + |
| 93 | +* Filename :filename:`example.ads` contains |
| 94 | + |
| 95 | + .. code:: Ada |
| 96 | +
|
| 97 | + package Example is |
| 98 | + procedure Null_Procedure is null; |
| 99 | + procedure Needs_A_Stub; |
| 100 | + function Expression_Function return Integer is (1); |
| 101 | + end Example; |
| 102 | +
|
| 103 | +* :command:`gnatstub example.ads` will generate :filename:`example.adb` |
| 104 | + |
| 105 | + .. code:: Ada |
| 106 | +
|
| 107 | + pragma Ada_2012; |
| 108 | + package body Example is |
| 109 | +
|
| 110 | + ------------------ |
| 111 | + -- Needs_A_Stub -- |
| 112 | + ------------------ |
| 113 | +
|
| 114 | + procedure Needs_A_Stub is |
| 115 | + begin |
| 116 | + pragma Compile_Time_Warning |
| 117 | + (Standard.True, "Needs_A_Stub unimplemented"); |
| 118 | + raise Program_Error with "Unimplemented procedure Needs_A_Stub"; |
| 119 | + end Needs_A_Stub; |
| 120 | +
|
| 121 | + end Example; |
| 122 | +
|
| 123 | +---------------------- |
| 124 | +Example Package Body |
| 125 | +---------------------- |
| 126 | + |
| 127 | +* Filename :filename:`example.adb` contains |
| 128 | + |
| 129 | + .. code:: Ada |
| 130 | +
|
| 131 | + package body Example is |
| 132 | + procedure Do_Something_Else; |
| 133 | + procedure Do_Something is separate; |
| 134 | + procedure Do_Something_Else is |
| 135 | + begin |
| 136 | + Do_Something; |
| 137 | + end Do_Something_Else; |
| 138 | + end Example; |
| 139 | +
|
| 140 | +* :command:`gnatstub --subunits example.adb` will generate :filename:`example-do_something.adb` |
| 141 | + |
| 142 | + .. code:: Ada |
| 143 | +
|
| 144 | + pragma Ada_2012; |
| 145 | + separate (Example) |
| 146 | + procedure Do_Something is |
| 147 | + begin |
| 148 | + pragma Compile_Time_Warning (Standard.True, "Do_Something unimplemented"); |
| 149 | + raise Program_Error with "Unimplemented procedure Do_Something"; |
| 150 | + end Do_Something; |
| 151 | +
|
| 152 | +=============================== |
| 153 | +:toolname:`GNATstub` Switches |
| 154 | +=============================== |
| 155 | + |
| 156 | +---------------------------------- |
| 157 | +Controlling Behavior When Called |
| 158 | +---------------------------------- |
| 159 | + |
| 160 | +* By default, a stubbed subprogram will raise :ada:`Program_Error` when called |
| 161 | + |
| 162 | + * Procedures use a :ada:`raise` statement |
| 163 | + * Functions use a :ada:`raise` expression in a :ada:`return` |
| 164 | + |
| 165 | + * To prevent warnings about no return in a function |
| 166 | + |
| 167 | +* You can disable the exception in procedures |
| 168 | + |
| 169 | + * Switch :command:`--no-exception` |
| 170 | + |
| 171 | +.. warning:: Functions still need a return statement, so :ada:`raise` expression is still present |
| 172 | + |
| 173 | +--------------------------- |
| 174 | +Formatting Comment Blocks |
| 175 | +--------------------------- |
| 176 | + |
| 177 | +* Sometimes you use :toolname:`GNATstub` to create a shell for your implementation |
| 178 | + |
| 179 | + * Having the tool populate the shell with comments can be helpful |
| 180 | + |
| 181 | +* Comment switches: |
| 182 | + |
| 183 | + :command:`--comment-header-sample` |
| 184 | + |
| 185 | + Create a file header comment block |
| 186 | + |
| 187 | + :command:`--comment-header-spec` |
| 188 | + |
| 189 | + Copy file header from spec into body |
| 190 | + |
| 191 | + :command:`--header-file=<filename>` |
| 192 | + |
| 193 | + Insert the contents of :filename:`<filename>` at the beginning of the stub body |
| 194 | + |
| 195 | +* Default behavior is to add a comment block for each subprogram |
| 196 | + |
| 197 | + * Use :command:`--no-local-header` to disable this |
| 198 | + |
| 199 | +----------------------- |
| 200 | +Other Common Switches |
| 201 | +----------------------- |
| 202 | + |
| 203 | +:command:`files=<filename>` |
| 204 | + |
| 205 | + :filename:`<filename>` contains a list of files for which stubs will be generated |
| 206 | + |
| 207 | +:command:`--force` |
| 208 | + |
| 209 | + Overwrite any existing file (without this, :toolname:`GNATstub` will flag as an error |
| 210 | + |
| 211 | +:command:`--output-dir=<directory>` |
| 212 | + |
| 213 | + Put generated files in :filename:`<directory>` |
| 214 | + |
| 215 | +:command:`max-line-length=<nnn>` |
| 216 | + |
| 217 | + Maximum length of line in generated body. Default is 79, maximum is 32767 |
| 218 | + |
| 219 | +===== |
| 220 | +Lab |
| 221 | +===== |
| 222 | + |
| 223 | +.. include:: labs/100_gnatstub/lab.rst |
| 224 | + |
| 225 | +========= |
| 226 | +Summary |
| 227 | +========= |
| 228 | + |
| 229 | +----------------------------------- |
| 230 | +Improving on :toolname:`GNATstub` |
| 231 | +----------------------------------- |
| 232 | + |
| 233 | +* Sometimes empty code stubs aren't enough |
| 234 | + |
| 235 | + * Not only don't they do anything useful, they actively raise compiler warnings and run-time exceptions! |
| 236 | + |
| 237 | +* "Smart" stubs are useful for testing |
| 238 | + |
| 239 | + * Replace code not available for testing |
| 240 | + * Control/replace external interfaces when testing natively |
| 241 | + |
| 242 | + * Read sensors |
| 243 | + * Write to a console |
| 244 | + |
| 245 | +* You can modify the generated stub(s) do implement all this |
| 246 | + |
| 247 | +----------------------------- |
| 248 | +Beyond :toolname:`GNATstub` |
| 249 | +----------------------------- |
| 250 | + |
| 251 | +* User-created "Smart" stubs are great for testing |
| 252 | + |
| 253 | + * But there's a lot of repetition in building the stubs |
| 254 | + * And maintenance can be difficult |
| 255 | + |
| 256 | +* Use :toolname:`GNATtest` to create more advanced unit tests |
| 257 | + |
| 258 | + * Expands on stubbing capabilities |
| 259 | + * Adds test driver generation |
| 260 | + * Adds automation capabilities |
| 261 | + |
| 262 | +For more information, go to :url:`GNATtest <https://www.adacore.com/dynamic-analysis/gnattest>` |
0 commit comments