trompeloeil

FORK: Header only C++14 mocking framework
git clone https://git.neptards.moe/u3shit/trompeloeil.git
Log | Files | Refs | README

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.