Backward.md (15058B)
1 # Backward compatibility with earlier versions of C\+\+ 2 3 - [Introduction](#introduction) 4 - [C\+\+11 compromises](#cxx11_compromises) 5 - [C\+\+11 API](#cxx11_api) 6 - [`REQUIRE_CALL` example](#cxx11_require_call) 7 - [`NAMED_REQUIRE_CALL` example](#cxx11_named_require_call) 8 - [`ALLOW_CALL` example](#cxx11_allow_call) 9 - [`NAMED_ALLOW_CALL` example](#cxx11_named_allow_call) 10 - [`FORBID_CALL` example](#cxx11_forbid_call) 11 - [`NAMED_FORBID_CALL` example](#cxx11_named_forbid_call) 12 - [Migrating from C\+\+11 API to C\+\+14 API](#migrate_to_cxx14) 13 - [Implicit conversion of `RETURN` modifier expression](#cxx11_return_implicit_conversion) 14 - [Macro expansion of `ANY` matcher before stringizing](#cxx11_any_stringizing) 15 - [G\+\+ 4.8.x limitations](#gxx48x_limitations) 16 - [Compiler defects](#gxx48x_compiler) 17 - [Rvalue reference failures](gxx48x_compiler_rvalue_ref) 18 - [Overload failures](#gxx48x_compiler_overload) 19 - [! matcher failures](#gxx48x_compiler_neg_matcher) 20 - [ANY matcher failures](#gxx48x_compiler_any_matcher) 21 - [Summary of compiler matcher failures](#gxx48x_compiler_matcher_summary) 22 - [Standard library defects](#gxx48x_library) 23 - [Regular expressions](#gxx48x_library_regex) 24 - [`<tuple>`](#gxx48x_library_tuple) 25 26 ## <A name="introduction"/> Introduction 27 28 Trompeloeil is a C\+\+14-first library and looks forward to the future 29 where C\+\+17-and-beyond language features and standard library 30 further improve its utility and performance. 31 32 Sometimes though, a project comes along where instead of looking forward 33 one has to look backward. How far backward? All the way back to 34 `g++-4.8.4` with a vintage `libstdc++-v3` library and requirements for 35 compliance with the features available in the C\+\+11 standard without 36 compiler extensions. (Indeed, it might be much worse: you might have 37 a project forced to use `g++-4.8.3` with further constraints.) 38 39 To allow you to consider Trompeloeil as your mock object framework 40 for a project with these constraints, we have back ported Trompeloeil to 41 `g++-4.8.4` (C\+\+11, `libstdc++-v3`) with an API that may be used with 42 a C\+\+11 dialect selected. The C\+\+11 API remains supported when a C\+\+14 43 (or later) dialect is selected. 44 45 ## <A name="cxx11_compromises"/> C\+\+11 compromises 46 47 Two major changes to functionality occur when compiling with the C\+\+11 dialect. 48 49 First, the API for defining expectations is different from the API used in 50 C\+\+14 and later dialects. 51 52 Second, the argument to a [**`RETURN`**](reference.md/#RETURN) modifier 53 undergoes an implicit conversion before semantic analysis. This results in 54 a different error message when the expression cannot be implicitly converted 55 to the return type of the function for which the expectation is being defined. 56 57 A minor change is that the expansion of the [**`ANY`**](reference.md/#ANY) 58 matcher in arguments to expectations is stringized differently in the 59 C\+\+11 API when compared to the C\+\+14 API. 60 61 ### <A name="cxx11_api"/> C\+\+11 API 62 63 It has not been possible to replicate the macro syntax that is used in 64 the C\+\+14 API. The cause is an inability to find a mechanism to 65 communicate sufficient type information between expectation macros and 66 modifier macros. 67 68 Our approach has been to redefine expectation macros as taking the 69 modifiers, if any, as an argument to the expectation macro. 70 71 The C\+\+11 API has a similar name to the corresponding C\+\+14 API 72 73 ```text 74 C++14 API C++11 API 75 ------------------------------ -------------------------------- 76 TROMPELOEIL_REQUIRE_CALL TROMPELOEIL_REQUIRE_CALL_V 77 TROMPELOEIL_NAMED_REQUIRE_CALL TROMPELOEIL_NAMED_REQUIRE_CALL_V 78 TROMPELOEIL_ALLOW_CALL TROMPELOEIL_ALLOW_CALL_V 79 TROMPELOEIL_NAMED_ALLOW_CALL TROMPELOEIL_NAMED_ALLOW_CALL_V 80 TROMPELOEIL_FORBID_CALL TROMPELOEIL_FORBID_CALL_V 81 TROMPELOEIL_NAMED_FORBID_CALL TROMPELOEIL_NAMED_FORBID_CALL_V 82 ``` 83 84 Short names for these macros have also been defined. 85 86 ```text 87 Short macro name Long macro name 88 -------------------- -------------------------------- 89 REQUIRE_CALL_V TROMPELOEIL_REQUIRE_CALL_V 90 NAMED_REQUIRE_CALL_V TROMPELOEIL_NAMED_REQUIRE_CALL_V 91 ALLOW_CALL_V TROMPELOEIL_ALLOW_CALL_V 92 NAMED_ALLOW_CALL_V TROMPELOEIL_NAMED_ALLOW_CALL_V 93 FORBID_CALL_V TROMPELOEIL_FORBID_CALL_V 94 NAMED_FORBID_CALL_V TROMPELOEIL_NAMED_FORBID_CALL_V 95 ``` 96 97 In the C\+\+11 API, the expectation macros accept two or more 98 arguments, the first two being object and function and the remainder 99 being the modifiers, if any. Therefore the `_V` suffix 100 may be read as an abbreviation of the word "variadic". 101 102 All documentation in Trompeloeil outside of this note uses the C\+\+14 API. 103 The examples below show how to translate from the C\+\+14 API to the C\+\+11 104 API. 105 106 #### <A name="cxx11_require_call"/> `REQUIRE_CALL` example 107 108 Given mock class `mock_c` with mock function `int getter(int)`, 109 110 ```cpp 111 struct mock_c 112 { 113 MAKE_MOCK1(getter, int(int)); 114 }; 115 ``` 116 117 and this expectation defined using the C\+\+14 API, 118 119 ```cpp 120 mock_c obj; 121 122 // Two macros adjacent to each other in the program text. 123 REQUIRE_CALL(obj, getter(ANY(int))) 124 .RETURN(_1); 125 ``` 126 127 the corresponding expectation implemented using the C\+\+11 API is 128 129 ```cpp 130 mock_c obj; 131 132 // One macro with three arguments. 133 REQUIRE_CALL_V(obj, getter(ANY(int)), 134 .RETURN(_1)); 135 ``` 136 137 See also: [**`REQUIRE_CALL(...)`**](reference.md/#REQUIRE_CALL). 138 139 #### <A name="cxx11_named_require_call"/> `NAMED_REQUIRE_CALL` example 140 141 Given mock class `mock_c` with mock function `int getter(int)`, 142 143 ```cpp 144 struct mock_c 145 { 146 MAKE_MOCK1(getter, int(int)); 147 }; 148 ``` 149 150 and this expectation defined using the C\+\+14 API, 151 152 ```cpp 153 mock_c obj; 154 155 // Two macros adjacent to each other in the program text. 156 auto e = NAMED_REQUIRE_CALL(obj, getter(ANY(int))) 157 .RETURN(0); 158 ``` 159 160 the corresponding expectation implemented using the C\+\+11 API is 161 162 ```cpp 163 mock_c obj; 164 165 // One macro with three arguments. 166 auto e = NAMED_REQUIRE_CALL_V(obj, getter(ANY(int)), 167 .RETURN(0)); 168 ``` 169 170 See also: [**`NAMED_REQUIRE_CALL(...)`**](reference.md/#NAMED_REQUIRE_CALL). 171 172 #### <A name="cxx11_allow_call"/> `ALLOW_CALL` example 173 174 Given mock class `mock_c` with mock function `int count()`, 175 176 ```cpp 177 struct mock_c 178 { 179 MAKE_MOCK0(count, int()); 180 }; 181 ``` 182 183 and this expectation defined using the C\+\+14 API, 184 185 ```cpp 186 mock_c obj; 187 188 // Two macros adjacent to each other in the program text. 189 ALLOW_CALL(obj, count()) 190 .RETURN(1); 191 ``` 192 193 the corresponding expectation implemented using the C\+\+11 API is, 194 195 ```cpp 196 mock_c obj; 197 198 // One macro with three arguments. 199 ALLOW_CALL_V(obj, count(), 200 .RETURN(1)); 201 ``` 202 203 See also: [**`ALLOW_CALL(...)`**](reference.md/#ALLOW_CALL). 204 205 #### <A name="cxx11_named_allow_call"/> `NAMED_ALLOW_CALL` example 206 207 Given mock class `mock_c` with mock function `int count()`, 208 209 ```cpp 210 struct mock_c 211 { 212 MAKE_MOCK0(count, int()); 213 }; 214 ``` 215 216 and this expectation defined using the C\+\+14 API, 217 218 ```cpp 219 mock_c obj; 220 221 // Two macros adjacent to each other in the program text. 222 auto e = NAMED_ALLOW_CALL(obj, count()) 223 .RETURN(1); 224 ``` 225 226 the corresponding expectation implemented using the C\+\+11 API is, 227 228 ```cpp 229 mock_c obj; 230 231 // One macro with three arguments. 232 auto e = NAMED_ALLOW_CALL_V(obj, count(), 233 .RETURN(1)); 234 ``` 235 236 See also: [**`NAMED_ALLOW_CALL(...)`**](reference.md/#NAMED_ALLOW_CALL). 237 238 #### <A name="cxx11_forbid_call"/> `FORBID_CALL` example 239 240 Given mock class `mock_c` with mock function `int count()`, 241 242 ```cpp 243 struct mock_c 244 { 245 MAKE_MOCK0(count, int()); 246 }; 247 ``` 248 249 and this expectation defined using the C\+\+14 API, 250 251 ```cpp 252 mock_c obj; 253 254 FORBID_CALL(obj, count()); 255 ``` 256 257 the corresponding expectation implemented using the C\+\+11 API is, 258 259 ```cpp 260 mock_c obj; 261 262 FORBID_CALL_V(obj, count()); 263 ``` 264 265 See also: [**`FORBID_CALL(...)`**](reference.md/#FORBID_CALL). 266 267 #### <A name="cxx11_named_forbid_call"/> `NAMED_FORBID_CALL` example 268 269 Given mock class `mock_c` with mock function `int count()`, 270 271 ```cpp 272 struct mock_c 273 { 274 MAKE_MOCK0(count, int()); 275 }; 276 ``` 277 278 and this expectation defined using the C\+\+14 API, 279 280 ```cpp 281 mock_c obj; 282 283 auto e = NAMED_FORBID_CALL(obj, count()); 284 ``` 285 286 the corresponding expectation implemented using the C\+\+11 API is, 287 288 ```cpp 289 mock_c obj; 290 291 auto e = NAMED_FORBID_CALL_V(obj, count()); 292 ``` 293 294 See also: [**`NAMED_FORBID_CALL(...)`**](reference.md/#NAMED_FORBID_CALL). 295 296 #### <A name="migrate_to_cxx14"/> Migrating from C\+\+11 API to C\+\+14 API 297 298 The C\+\+11 API remains available when changing your C\+\+ dialect to C\+\+14 299 or later. Therefore existing test cases may be migrated incrementally 300 to the C\+\+14 API while using the C\+\+14 API for new test cases. 301 302 Steps: 303 304 - Remove the `_V` suffix from the expectation macro. 305 - Move the modifiers, if any, outside the argument list of the 306 expectation macro. 307 - Remove workarounds such as 308 - Changes to regular expressions that may be testing messages generated 309 with the `ANY` matcher. 310 - Any of the workarounds required to use Trompeloeil with `g++ 4.8.3`. 311 312 For example, given this expectation using the C\+\+11 API, 313 314 ```cpp 315 trompeloeil::sequence seq; 316 317 auto thrown = false; 318 319 REQUIRE_CALL_V(obj, getter(ANY(int)), 320 .IN_SEQUENCE(seq) 321 .LR_SIDE_EFFECT(thrown = true) 322 .THROW(_1)); 323 ``` 324 325 the corresponding C\+\+14 API implementation is, 326 327 ```cpp 328 trompeloeil::sequence seq; 329 330 auto thrown = false; 331 332 REQUIRE_CALL(obj, getter(ANY(int))) 333 .IN_SEQUENCE(seq) 334 .LR_SIDE_EFFECT(thrown = true) 335 .THROW(_1); 336 ``` 337 338 ### <A name="cxx11_return_implicit_conversion"/> Implicit conversion of `RETURN` modifier expression 339 340 In the C\+\+14 API, the [**`RETURN(...)`**](reference.md/#RETURN) 341 modifier stores the expression passed as an argument to the 342 modifier and forwards it to the Trompeloeil implementation 343 for semantic analysis. 344 345 In the C\+\+11 API, not only is the expression stored but also an 346 implicit conversion to the return type of the mocked function 347 is performed. This implicit conversion may fail before 348 semantic checks are performed. 349 350 The result is that instead of a helpful message generated by 351 a `static_assert`, a less helpful error message is generated 352 by the compiler. 353 354 For example, 355 356 ```cpp 357 struct MS 358 { 359 MAKE_MOCK0(f, char&()); 360 }; 361 362 int main() 363 { 364 MS obj; 365 366 REQUIRE_CALL_V(obj, f(), 367 .RETURN('a')); 368 } 369 ``` 370 371 The C\+\+11 error message is, 372 373 ```text 374 error: invalid initialization of non-const reference of type 375 ‘MS::trompeloeil_l_tag_type_trompeloeil_20::return_of_t {aka char&}’ 376 from an rvalue of type ‘char’ 377 ``` 378 379 The C\+\+14 error message is, 380 381 ```text 382 error: static assertion failed: 383 RETURN non-reference from function returning reference 384 ``` 385 386 Other error messages that may not be generated while compiling using 387 a C\+\+11 dialect include: 388 389 ```text 390 RETURN const* from function returning pointer to non-const 391 392 RETURN const& from function returning non-const reference 393 394 RETURN value is not convertible to the return type of the function 395 ``` 396 397 This is a quality of implementation issue that wasn't resolved before 398 the C\+\+11 API became available. 399 400 ### <A name="cxx11_any_stringizing"/> Macro expansion of `ANY` matcher before stringizing 401 402 Macro expansion differences between C\+\+11 and C\+\+14 expectation macros 403 mean macros like the [**`ANY(...)`**](reference.md/#ANY_MACRO) matcher 404 used in the parameter list of the function to match are expanded in 405 C\+\+11 before they are stringized. 406 407 For example, a regular expression written in a C\+\+14 dialect, or later, 408 409 ```cpp 410 auto re = R":(Sequence expectations not met at destruction of sequence object "s": 411 missing obj\.getter\(ANY\(int\)\) at [A-Za-z0-9_ ./:\]*:[0-9]*.* 412 missing obj\.foo\(_\) at [A-Za-z0-9_ ./:\]*:[0-9]*.* 413 ):"; 414 ``` 415 416 won't match the string generated when running in a C\+\+11 dialect. 417 The `ANY(int)` matcher is actually expanded to some Trompeloeil-internal data. 418 419 A helper macro, such as `CXX11_AS_STRING()`, may be defined to give a 420 stringized form correct for C\+\+11: 421 422 ```cpp 423 #define CXX11_AS_STRING_IMPL(x) #x 424 #define CXX11_AS_STRING(x) CXX11_AS_STRING_IMPL(x) 425 ``` 426 427 It may be used in constructing larger strings. Rewriting the example above 428 illustrates its use: 429 430 ```cpp 431 auto re = R":(Sequence expectations not met at destruction of sequence object "s": 432 missing obj\.getter\():" + 433 escape_parens(CXX11_AS_STRING(ANY(int))) + 434 R":(\) at [A-Za-z0-9_ ./:\]*:[0-9]*.* 435 missing obj\.foo\(_\) at [A-Za-z0-9_ ./:\]*:[0-9]*.* 436 ):"; 437 ``` 438 439 where `escape_parens()` performs escaping of parentheses in the input string, 440 441 ```cpp 442 std::string escape_parens(const std::string& s) 443 { 444 constexpr auto backslash = '\\'; 445 446 std::string tmp; 447 448 for (auto& c : s) 449 { 450 if (c == '(' || c == ')') 451 { 452 tmp += backslash; 453 } 454 455 tmp += c; 456 } 457 458 return tmp; 459 } 460 ``` 461 462 This is a quality of implementation issue that wasn't resolved before 463 the C\+\+11 API became available. 464 465 ## <A name="gxx48x_limitations"/> G\+\+ 4.8.x limitations 466 467 Trompeloeil's support for `g++ 4.8.x` is limited by compiler and standard 468 library defects. 469 470 ### <A name="gxx48x_compiler"/> Compiler defects 471 472 `g++-4.8.3` and older suffers from [bug 58714]( 473 https://gcc.gnu.org/bugzilla/show_bug.cgi?id=58714) which causes the 474 wrong overload to be selected when overloads for mock functions exists 475 for both `T&&` and `const T&` parameters. 476 477 Example: 478 479 ```Cpp 480 struct S 481 { 482 MAKE_MOCK1(func, void(const int&)); 483 MAKE_MOCK1(func, void(int&&)); 484 }; 485 486 void test() 487 { 488 S s; 489 REQUIRE_CALL_V(s, func(ANY(const int&))); 490 491 const int i = 0; 492 s.func(i); 493 } 494 ``` 495 496 With `g++-4.8.3` and older, this is reported as: 497 498 ```text 499 No match for call of func with signature void(const int&) with. 500 501 param _1 == 1 502 ``` 503 504 because the expectation is wrongly placed on the `int&&` overload. 505 506 Consider moving to a more modern compiler. 507 508 ### <A name="gxx48x_library"/> Standard library defects 509 510 #### <A name="gxx48x_library_regex"/> Regular expressions 511 512 `g++ 4.8.x` lacks support for regular expressions in `libstdc++-v3`. 513 514 As Jonathan Wakely said, 515 > *sigh* \<regex\> is not implemented prior to GCC 4.9.0, 516 > I thought the whole world was aware of that by now. 517 518 See: GCC Bugzilla, "Bug 61582 - C\+\+11 regex memory corruption," 519 23 June 2014. \ 520 Available: <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61582> \ 521 Accessed: 9 November 2017 522 523 As a consequence, avoid the [**`re(...)`**](reference.md/#re) matcher 524 in test cases when compiling with a C\+\+11 dialect. 525 526 #### <A name="gxx48x_library_tuple"/> `<tuple>` 527 528 `g++-4.8.3` has a defect in `<tuple>` in `libstdc++-v3`. 529 530 See: GCC Bugzilla, "Bug 61947 - [4.8/4.9 Regression] Ambiguous calls when constructing std::tuple," 531 29 July 2014. \ 532 Available: <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61947> \ 533 Accessed: 8 November 2017 534 535 This is fixed in `g++-4.8.4`, `g++-4.9.3` and later releases. 536 537 One workaround for this defect is to copy a version of `<tuple>` from a 538 release of `g++-4.8.4` or `g++-4.8.5` and arrange to include it 539 ahead of the buggy version. Then work hard to move forward to a more recent 540 compiler release.