LCOV - code coverage report
Current view: top level - tests - catch_reporter_executor.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 1493 1547 96.5 %
Date: 2024-09-14 18:11:21 Functions: 26 26 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : // Copyright (c) 2012-2024  Made to Order Software Corp.  All Rights Reserved
       2             : //
       3             : // https://snapwebsites.org/project/eventdispatcher
       4             : // contact@m2osw.com
       5             : //
       6             : // This program is free software: you can redistribute it and/or modify
       7             : // it under the terms of the GNU General Public License as published by
       8             : // the Free Software Foundation, either version 3 of the License, or
       9             : // (at your option) any later version.
      10             : //
      11             : // This program is distributed in the hope that it will be useful,
      12             : // but WITHOUT ANY WARRANTY; without even the implied warranty of
      13             : // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      14             : // GNU General Public License for more details.
      15             : //
      16             : // You should have received a copy of the GNU General Public License
      17             : // along with this program.  If not, see <https://www.gnu.org/licenses/>.
      18             : 
      19             : // this diagnostic has to be turned off "globally" so the catch2 does not
      20             : // generate the warning on the floating point == operator
      21             : //
      22             : #pragma GCC diagnostic ignored "-Wfloat-equal"
      23             : 
      24             : // self
      25             : //
      26             : #include    "catch_main.h"
      27             : 
      28             : 
      29             : 
      30             : // reporter
      31             : //
      32             : #include    <eventdispatcher/reporter/executor.h>
      33             : 
      34             : #include    <eventdispatcher/reporter/parser.h>
      35             : #include    <eventdispatcher/reporter/variable_address.h>
      36             : #include    <eventdispatcher/reporter/variable_floating_point.h>
      37             : #include    <eventdispatcher/reporter/variable_integer.h>
      38             : #include    <eventdispatcher/reporter/variable_list.h>
      39             : #include    <eventdispatcher/reporter/variable_regex.h>
      40             : #include    <eventdispatcher/reporter/variable_string.h>
      41             : #include    <eventdispatcher/reporter/variable_timestamp.h>
      42             : #include    <eventdispatcher/reporter/variable_void.h>
      43             : 
      44             : 
      45             : // libaddr
      46             : //
      47             : #include    <libaddr/addr_parser.h>
      48             : 
      49             : 
      50             : // eventdispatcher
      51             : //
      52             : #include    <eventdispatcher/communicator.h>
      53             : #include    <eventdispatcher/tcp_client_permanent_message_connection.h>
      54             : 
      55             : 
      56             : // last include
      57             : //
      58             : #include    <snapdev/poison.h>
      59             : 
      60             : 
      61             : 
      62             : namespace
      63             : {
      64             : 
      65             : 
      66             : 
      67             : constexpr char const * const g_program_sleep_func =
      68             :     "call(label: func_sleep)\n"
      69             :     "exit(timeout: 1)\n"
      70             :     "label(name: func_sleep)\n"
      71             :     "sleep(seconds: 2.5)\n"
      72             :     "return()\n"
      73             : ;
      74             : 
      75             : constexpr char const * const g_program_start_thread =
      76             :     "set_variable(name: test, value: 33)\n"
      77             :     "set_variable(name: test_copy_between_dollars, value: \"$${test}$\")\n"
      78             :     "run()\n"
      79             :     "set_variable(name: runner, value: 6.07)\n"
      80             :     "set_variable(name: runner_copy_as_is, value: \"runner = ${runner}\")\n"
      81             :     "set_variable(name: time_limit, value: @1713934141.107805991)\n"
      82             :     "set_variable(name: time_limit_copy, value: \"limit: ${time_limit}\")\n"
      83             :     "set_variable(name: host_ip, value: <127.7.3.51>)\n"
      84             :     "set_variable(name: host_ip_copy, value: \"Host is at ${host_ip} address\")\n"
      85             :     "set_variable(name: time_and_host_ip, value: \"time ${time_limit} and address ${host_ip}...\")\n"
      86             : ;
      87             : 
      88             : constexpr char const * const g_program_start_thread_twice =
      89             :     "set_variable(name: test, value: 33)\n"
      90             :     "run()\n"
      91             :     "set_variable(name: runner, value: 6.07)\n"
      92             :     "run()\n" // second run() is forbidden
      93             : ;
      94             : 
      95             : constexpr char const * const g_program_verify_computation_integer =
      96             :     "set_variable(name: t01, value: 3)\n"
      97             : 
      98             :     "set_variable(name: t11, value: -3)\n"
      99             :     "set_variable(name: t12, value: +3)\n"
     100             : 
     101             :     "set_variable(name: t21, value: 3 + 2)\n"
     102             :     "set_variable(name: t22, value: -(3 + 2))\n"
     103             :     "set_variable(name: t23, value: 20 - 4)\n"
     104             :     "set_variable(name: t24, value: 3 * 2)\n"
     105             :     "set_variable(name: t25, value: 20 / 4)\n"
     106             :     "set_variable(name: t26, value: 27 % 11)\n"
     107             : 
     108             :     "set_variable(name: t31, value: 3 + 2 * 5)\n"
     109             :     "set_variable(name: t32, value: -7 + 15 / 3)\n"
     110             :     "set_variable(name: t33, value: +2 + 15 % 7)\n"
     111             : 
     112             :     "set_variable(name: t41, value: (3 + 2) * 5)\n"
     113             :     "set_variable(name: t42, value: (-7 + 15) / 3)\n"
     114             :     "set_variable(name: t43, value: (+2 + 15) % 7)\n"
     115             : ;
     116             : 
     117             : constexpr char const * const g_program_verify_computation_floating_point =
     118             :     "set_variable(name: t01, value: 3.01)\n"
     119             : 
     120             :     "set_variable(name: t11, value: -3.5)\n"
     121             :     "set_variable(name: t12, value: +3.2)\n"
     122             : 
     123             :     "set_variable(name: t21ff, value: 3.01 + 2.45)\n"
     124             :     "set_variable(name: t21if, value: 3 + 2.54)\n"
     125             :     "set_variable(name: t21fi, value: 3.01 + 2)\n"
     126             :     "set_variable(name: t22ff, value: -(3.5 + 2.5))\n"
     127             :     "set_variable(name: t22if, value: -(3 + 2.11))\n"
     128             :     "set_variable(name: t22fi, value: -(3.07 + 2))\n"
     129             :     "set_variable(name: t23ff, value: 20.07 - 4.13)\n"
     130             :     "set_variable(name: t23if, value: 20 - 4.78)\n"
     131             :     "set_variable(name: t23fi, value: 20.91 - 4)\n"
     132             :     "set_variable(name: t24ff, value: 3.41 * 2.14)\n"
     133             :     "set_variable(name: t24if, value: 3 * 2.67)\n"
     134             :     "set_variable(name: t24fi, value: 3.32 * 2)\n"
     135             :     "set_variable(name: t25ff, value: 20.83 / 4.07)\n"
     136             :     "set_variable(name: t25if, value: 20 / 4.4)\n"
     137             :     "set_variable(name: t25fi, value: 20.93 / 4)\n"
     138             :     "set_variable(name: t26ff, value: 27.27 % 11.11)\n"
     139             :     "set_variable(name: t26if, value: 27 % 11.88)\n"
     140             :     "set_variable(name: t26fi, value: 27.72 % 11)\n"
     141             : 
     142             :     "set_variable(name: t31fff, value: 3.03 + 2.2 * 5.9)\n"
     143             :     "set_variable(name: t31iff, value: 3 + 2.5 * 5.7)\n"
     144             :     "set_variable(name: t31fif, value: 3.2 + 2 * 5.3)\n"
     145             :     "set_variable(name: t31ffi, value: 3.07 + 2.28 * 5)\n"
     146             :     "set_variable(name: t31iif, value: 3 + 2 * 5.67)\n"
     147             :     "set_variable(name: t31ifi, value: 3 + 2.56 * 5)\n"
     148             :     "set_variable(name: t31fii, value: 3.33 + 2 * 5)\n"
     149             :     "set_variable(name: t32fff, value: -7.11 + 15.7 / 3.06)\n"
     150             :     "set_variable(name: t32iff, value: -7 + 15.25 / 3.31)\n"
     151             :     "set_variable(name: t32fif, value: -7.78 + 15 / 3.77)\n"
     152             :     "set_variable(name: t32ffi, value: -7.09 + 15.34 / 3)\n"
     153             :     "set_variable(name: t32iif, value: -7 + 15 / 3.30)\n"
     154             :     "set_variable(name: t32ifi, value: -7 + 15.09 / 3)\n"
     155             :     "set_variable(name: t32fii, value: -7.94 + 15 / 3)\n"
     156             :     "set_variable(name: t33fff, value: +2.21 + 15.16 % 7.8)\n"
     157             :     "set_variable(name: t33iff, value: +2 + 15.12 % 7.93)\n"
     158             :     "set_variable(name: t33fif, value: +2.58 + 15 % 7.63)\n"
     159             :     "set_variable(name: t33ffi, value: +2.12 + 15.09 % 7)\n"
     160             :     "set_variable(name: t33iif, value: +2 + 15 % 7.19)\n"
     161             :     "set_variable(name: t33ifi, value: +2 + 15.18 % 7)\n"
     162             :     "set_variable(name: t33fii, value: +2.17 + 15 % 7)\n"
     163             : 
     164             :     "set_variable(name: t41fff, value: (3.45 + 2.06) * 5.55)\n"
     165             :     "set_variable(name: t41iff, value: (3 + 2.17) * 5.07)\n"
     166             :     "set_variable(name: t41fif, value: (3.37 + 2) * 5.12)\n"
     167             :     "set_variable(name: t41ffi, value: (3.45 + 2.67) * 5)\n"
     168             :     "set_variable(name: t41iif, value: (3 + 2) * 5.3)\n"
     169             :     "set_variable(name: t41ifi, value: (3 + 2.9) * 5)\n"
     170             :     "set_variable(name: t41fii, value: (3.4 + 2) * 5)\n"
     171             :     "set_variable(name: t42fff, value: (-7.4 + 15.15) / 3.93)\n"
     172             :     "set_variable(name: t42iff, value: (-7 + 15.21) / 3.43)\n"
     173             :     "set_variable(name: t42fif, value: (-7.72 + 15) / 3.31)\n"
     174             :     "set_variable(name: t42ffi, value: (-7.43 + 15.89) / 3)\n"
     175             :     "set_variable(name: t42iif, value: (-7 + 15) / 3.4)\n"
     176             :     "set_variable(name: t42ifi, value: (-7 + 15.09) / 3)\n"
     177             :     "set_variable(name: t42fii, value: (-7.73 + 15) / 3)\n"
     178             :     "set_variable(name: t43fff, value: (+2.25 + 15.36) % 7.47)\n"
     179             :     "set_variable(name: t43iff, value: (+2 + 15.16) % 7.38)\n"
     180             :     "set_variable(name: t43fif, value: (+2.51 + 15) % 7.59)\n"
     181             :     "set_variable(name: t43ffi, value: (+2.4 + 15.3) % 7)\n"
     182             :     "set_variable(name: t43iif, value: (+2 + 15) % 7.0)\n"
     183             :     "set_variable(name: t43ifi, value: (+2 + 15.8) % 7)\n"
     184             :     "set_variable(name: t43fii, value: (+2.07 + 15) % 7)\n"
     185             : ;
     186             : 
     187             : constexpr char const * const g_program_verify_computation_timestamp =
     188             :     "set_variable(name: t01, value: @123 + 5)\n"
     189             :     "set_variable(name: t02, value: 33 + @123)\n"
     190             :     "set_variable(name: t03, value: @123 - 5)\n"
     191             :     "set_variable(name: t04, value: 33 - @123)\n"
     192             : 
     193             :     "set_variable(name: t11, value: @123 + 5.09)\n"
     194             :     "set_variable(name: t12, value: 33.501923821 + @123)\n"
     195             :     "set_variable(name: t13, value: @123 - 5.001)\n"
     196             :     "set_variable(name: t14, value: 333.98201992 - @123)\n"
     197             : 
     198             :     "set_variable(name: t21, value: -@123)\n"
     199             :     "set_variable(name: t22, value: +@123)\n"
     200             : 
     201             :     "set_variable(name: t31, value: @300.561 - @123.231)\n"
     202             :     "set_variable(name: t32, value: @34.3123 + @123.9984312)\n"
     203             : ;
     204             : 
     205             : constexpr char const * const g_program_verify_now =
     206             :     "now(variable_name: about_now)\n"
     207             : ;
     208             : 
     209             : constexpr char const * const g_program_verify_computation_address =
     210             :     "set_variable(name: t01, value: <127.0.0.1> + 256)\n"
     211             :     "set_variable(name: t02, value: 256 + <192.168.3.57>)\n"
     212             :     "set_variable(name: t03, value: <172.131.4.1> - 256)\n"
     213             : 
     214             :     "set_variable(name: t11, value: <10.5.34.255> - <10.5.33.0>)\n"
     215             : ;
     216             : 
     217             : constexpr char const * const g_program_verify_computation_concatenation =
     218             :     "set_variable(name: t01, value: ident + ifier)\n"
     219             : 
     220             :     "set_variable(name: t11, value: 'single' + ' ' + 'string')\n"
     221             :     "set_variable(name: t12, value: 'single' + \" \" + 'string')\n"
     222             :     "set_variable(name: t13, value: 'single' + ' ' + \"string\")\n"
     223             :     "set_variable(name: t14, value: \"double\" + \" \" + \"string\")\n"
     224             : 
     225             :     "set_variable(name: t21, value: +identify)\n"
     226             :     "set_variable(name: t22, value: +'single string')\n"
     227             :     "set_variable(name: t23, value: +\"double string\")\n"
     228             : 
     229             :     "set_variable(name: t31, value: 'single' + 36)\n"
     230             :     "set_variable(name: t32, value: 258 + 'single')\n"
     231             :     "set_variable(name: t33, value: \"string\" + 102)\n"
     232             :     "set_variable(name: t34, value: 5005 + \"double\")\n"
     233             : ;
     234             : 
     235             : constexpr char const * const g_program_verify_computation_string_repeat =
     236             :     "set_variable(name: t01, value: 'abc' * 3)\n"
     237             :     "set_variable(name: t02, value: \"xyz\" * 5)\n"
     238             :     "set_variable(name: t03, value: \"zero\" * 0)\n"
     239             :     "set_variable(name: t04, value: \"one\" * 1)\n"
     240             : ;
     241             : 
     242             : constexpr char const * const g_program_verify_variable_in_string =
     243             :     "set_variable(name: foo, value: 'abc')\n"
     244             :     "set_variable(name: bar, value: \"[${foo}]\")\n"
     245             : ;
     246             : 
     247             : constexpr char const * const g_program_accept_one_message =
     248             :     "run()\n"
     249             :     "listen(address: <127.0.0.1:20002>)\n"
     250             :     "label(name: wait_message)\n"
     251             :     "clear_message()\n"
     252             :     "wait(timeout: 10.0, mode: wait)\n" // first wait reacts on connect(), second wait receives the REGISTER message
     253             :     "has_message()\n"
     254             :     "if(false: wait_message)\n"
     255             :     "show_message()\n"
     256             :     "verify_message(command: REGISTER, required_parameters: { service: responder, version: 1 }, optional_parameters: { commands: \"READY,HELP,STOP\" }, forbidden_parameters: { forbidden })\n"
     257             :     "save_parameter_value(parameter_name: version, variable_name: register_version)\n"
     258             :     "save_parameter_value(parameter_name: service, variable_name: register_service, type: identifier)\n"
     259             :     "send_message(command: READY, sent_server: reporter_test_extension, sent_service: test_processor, server: reporter_test, service: accept_one_message, parameters: { status: alive, version: 9 })\n"
     260             :     "wait(timeout: 10.0, mode: drain)\n"
     261             :     "disconnect()\n"
     262             :     "exit()\n"
     263             : ;
     264             : 
     265             : constexpr char const * const g_program_receive_unwanted_message =
     266             :     "run()\n"
     267             :     "listen(address: <127.0.0.1:20002>)\n"
     268             :     "label(name: wait_message)\n"
     269             :     "clear_message()\n"
     270             :     "wait(timeout: 10.0, mode: wait)\n"
     271             :     "has_message()\n"
     272             :     "if(false: wait_message)\n"
     273             :     "show_message()\n"
     274             :     "verify_message(command: REGISTER, required_parameters: { service: responder, version: `^[0-9]+$` }, optional_parameters: { commands: \"READY,HELP,STOP\" }, forbidden_parameters: { forbidden })\n"
     275             :     "save_parameter_value(parameter_name: version, variable_name: register_version, type: integer)\n"
     276             :     "send_message(command: READY, parameters: { version: 9 })\n"
     277             :     "print(message: \"nearly done\")\n"
     278             :     "exit(timeout: 2.5)\n"
     279             : ;
     280             : 
     281             : constexpr char const * const g_program_send_unsupported_message_parameter_type =
     282             :     "run()\n"
     283             :     "listen(address: <127.0.0.1:20002>)\n"
     284             :     "label(name: wait_message)\n"
     285             :     "clear_message()\n"
     286             :     "wait(timeout: 10.0, mode: wait)\n" // first wait reacts on connect(), second wait receives the REGISTER message
     287             :     "has_message()\n"
     288             :     "if(false: wait_message)\n"
     289             :     "show_message()\n"
     290             :     "verify_message(command: REGISTER, required_parameters: { service: responder, version: 1 }, optional_parameters: { commands: \"READY,HELP,STOP\" }, forbidden_parameters: { forbidden })\n"
     291             :     "save_parameter_value(parameter_name: version, variable_name: register_version, type: integer)\n"
     292             :     "send_message(command: READY, parameters: { status: 3.05 })\n" // floating point not yet supported
     293             :     "wait(timeout: 1.0, mode: drain)\n"
     294             : ;
     295             : 
     296             : constexpr char const * const g_program_send_invalid_parameter_value_type =
     297             :     "run()\n"
     298             :     "listen(address: <127.0.0.1:20002>)\n"
     299             :     "label(name: wait_message)\n"
     300             :     "clear_message()\n"
     301             :     "wait(timeout: 10.0, mode: wait)\n"
     302             :     "has_message()\n"
     303             :     "if(false: wait_message)\n"
     304             :     "show_message()\n"
     305             :     "verify_message(command: REGISTER, required_parameters: { service: responder, version: 1 }, optional_parameters: { commands: \"READY,HELP,STOP\" }, forbidden_parameters: { forbidden })\n"
     306             :     "save_parameter_value(parameter_name: service, variable_name: register_version, type: integer)\n" // service is not an integer
     307             :     "send_message(command: READY, parameters: { status: \"3.05\" })\n"
     308             :     "wait(timeout: 1.0, mode: drain)\n"
     309             : ;
     310             : 
     311             : constexpr char const * const g_program_save_parameter_of_type_timestamp =
     312             :     "run()\n"
     313             :     "listen(address: <127.0.0.1:20002>)\n"
     314             :     "label(name: wait_message)\n"
     315             :     "wait(timeout: 10.0, mode: wait)\n"
     316             :     "has_message()\n"
     317             :     "if(false: wait_message)\n"
     318             :     "show_message()\n"
     319             :     "verify_message(command: REGISTER, required_parameters: { service: responder, version: 1 }, optional_parameters: { commands: \"READY,HELP,STOP\" }, forbidden_parameters: { forbidden })\n"
     320             :     "save_parameter_value(parameter_name: version, variable_name: register_version, type: integer)\n"
     321             :     "save_parameter_value(parameter_name: large_number, variable_name: default_integer, type: integer)\n"
     322             :     "send_message(command: READY, parameters: { status: \"3.05\", date: @1715440881.543723981 })\n"
     323             :     "clear_message()\n"
     324             :     "label(name: wait_second_message)\n"
     325             :     "wait(timeout: 10.0, mode: wait)\n"
     326             :     "has_message()\n"
     327             :     "if(false: wait_second_message)\n"
     328             :     "show_message()\n"
     329             :     "verify_message(command: TIMED, required_parameters: { now: `^[0-9]+(\\\\.[0-9]+)?$` } )\n"
     330             :     "save_parameter_value(parameter_name: now, variable_name: timed_value, type: timestamp)\n"
     331             :     "save_parameter_value(parameter_name: not_defined, variable_name: default_time, type: timestamp)\n"
     332             :     "exit()\n"
     333             : ;
     334             : 
     335             : constexpr char const * const g_program_save_parameter_with_unknown_type =
     336             :     "run()\n"
     337             :     "listen(address: <127.0.0.1:20002>)\n"
     338             :     "label(name: wait_message)\n"
     339             :     "clear_message()\n"
     340             :     "wait(timeout: 10.0, mode: wait)\n"
     341             :     "has_message()\n"
     342             :     "if(false: wait_message)\n"
     343             :     "show_message()\n"
     344             :     "verify_message(command: REGISTER, required_parameters: { service: responder, version: 1 }, optional_parameters: { commands: \"READY,HELP,STOP\" }, forbidden_parameters: { forbidden })\n"
     345             :     "save_parameter_value(parameter_name: service, variable_name: register_version, type: void)\n" // "void" is not a supported type here
     346             :     "send_message(command: READY, parameters: { status: \"3.05\" })\n"
     347             :     "wait(timeout: 1.0, mode: drain)\n"
     348             : ;
     349             : 
     350             : constexpr char const * const g_program_undefined_variable =
     351             :     "has_type(name: undefined_variable, type: void)\n"
     352             :     "if(unordered: it_worked)\n"
     353             :     "exit(error_message: \"undefined variable not properly detected.\")\n"
     354             :     "label(name: it_worked)\n"
     355             :     "exit()\n"
     356             : ;
     357             : 
     358             : constexpr char const * const g_program_integer_variable =
     359             :     "set_variable(name: my_int, value: 33)\n"
     360             :     "has_type(name: my_int, type: string)\n"
     361             :     "if(false: not_string)\n"
     362             :     "exit(error_message: \"integer variable detected as a string.\")\n"
     363             :     "label(name: not_string)\n"
     364             :     "has_type(name: my_int, type: integer)\n"
     365             :     "if(true: is_integer)\n"
     366             :     "exit(error_message: \"integer variable not properly detected as such.\")\n"
     367             :     "label(name: is_integer)\n"
     368             :     "exit()\n"
     369             : ;
     370             : 
     371             : constexpr char const * const g_program_string_variable =
     372             :     "set_variable(name: my_str, value: \"3.3\")\n"
     373             :     "has_type(name: my_str, type: floating_point)\n"
     374             :     "if(false: not_floating_point)\n"
     375             :     "exit(error_message: \"string variable detected as a floating_point.\")\n"
     376             :     "label(name: not_floating_point)\n"
     377             :     "has_type(name: my_str, type: string)\n"
     378             :     "if(true: is_string)\n"
     379             :     "exit(error_message: \"string variable not properly detected as such.\")\n"
     380             :     "label(name: is_string)\n"
     381             :     "exit()\n"
     382             : ;
     383             : 
     384             : constexpr char const * const g_program_if_variable =
     385             :     "if(variable: not_defined, unordered: not_defined_worked)\n"
     386             :     "exit(error_message: \"if(variable: <undefined>) failed test.\")\n"
     387             :     "label(name: not_defined_worked)\n"
     388             : 
     389             :     // >, >=, !=, true, ordered
     390             :     "set_variable(name: my_var, value: 5)\n"
     391             :     "if(variable: my_var, greater: positive_greater_int_worked)\n"
     392             :     "exit(error_message: \"if(variable: <positive integer> + greater) failed test.\")\n"
     393             :     "label(name: positive_greater_int_worked)\n"
     394             :     "if(variable: my_var, greater_or_equal: positive_greater_or_equal_int_worked)\n"
     395             :     "exit(error_message: \"if(variable: <positive integer> + greater_or_equal) failed test.\")\n"
     396             :     "label(name: positive_greater_or_equal_int_worked)\n"
     397             :     "if(variable: my_var, not_equal: positive_not_equal_int_worked)\n"
     398             :     "exit(error_message: \"if(variable: <positive integer> + not_equal) failed test.\")\n"
     399             :     "label(name: positive_not_equal_int_worked)\n"
     400             :     "if(variable: my_var, true: positive_true_int_worked)\n"
     401             :     "exit(error_message: \"if(variable: <positive integer> + true) failed test.\")\n"
     402             :     "label(name: positive_true_int_worked)\n"
     403             :     "if(variable: my_var, ordered: positive_ordered_int_worked)\n"
     404             :     "exit(error_message: \"if(variable: <positive integer> + ordered) failed test.\")\n"
     405             :     "label(name: positive_ordered_int_worked)\n"
     406             : 
     407             :     // <, <=, !=, true, ordered
     408             :     "set_variable(name: my_var, value: -5)\n"
     409             :     "if(variable: my_var, less: negative_less_int_worked)\n"
     410             :     "exit(error_message: \"if(variable: <negative integer> + less) failed test.\")\n"
     411             :     "label(name: negative_less_int_worked)\n"
     412             :     "if(variable: my_var, less_or_equal: negative_less_or_equal_int_worked)\n"
     413             :     "exit(error_message: \"if(variable: <negative integer> + less_or_equal) failed test.\")\n"
     414             :     "label(name: negative_less_or_equal_int_worked)\n"
     415             :     "if(variable: my_var, not_equal: negative_not_equal_int_worked)\n"
     416             :     "exit(error_message: \"if(variable: <negative integer> + not_equal) failed test.\")\n"
     417             :     "label(name: negative_not_equal_int_worked)\n"
     418             :     "if(variable: my_var, true: negative_true_int_worked)\n"
     419             :     "exit(error_message: \"if(variable: <negative integer> + true) failed test.\")\n"
     420             :     "label(name: negative_true_int_worked)\n"
     421             :     "if(variable: my_var, ordered: negative_ordered_int_worked)\n"
     422             :     "exit(error_message: \"if(variable: <negative integer> + ordered) failed test.\")\n"
     423             :     "label(name: negative_ordered_int_worked)\n"
     424             : 
     425             :     // ==, false, ordered
     426             :     "set_variable(name: my_var, value: 0)\n"
     427             :     "if(variable: my_var, equal: zero_equal_int_worked)\n"
     428             :     "exit(error_message: \"if(variable: <zero integer> + equal) failed test.\")\n"
     429             :     "label(name: zero_equal_int_worked)\n"
     430             :     "if(variable: my_var, less_or_equal: zero_less_or_equal_int_worked)\n"
     431             :     "exit(error_message: \"if(variable: <negative integer> + less_or_equal) failed test.\")\n"
     432             :     "label(name: zero_less_or_equal_int_worked)\n"
     433             :     "if(variable: my_var, greater_or_equal: zero_greater_or_equal_int_worked)\n"
     434             :     "exit(error_message: \"if(variable: <negative integer> + greater_or_equal) failed test.\")\n"
     435             :     "label(name: zero_greater_or_equal_int_worked)\n"
     436             :     "if(variable: my_var, false: zero_false_int_worked)\n"
     437             :     "exit(error_message: \"if(variable: <negative integer> + false) failed test.\")\n"
     438             :     "label(name: zero_false_int_worked)\n"
     439             :     "if(variable: my_var, ordered: zero_ordered_int_worked)\n"
     440             :     "exit(error_message: \"if(variable: <negative integer> + ordered) failed test.\")\n"
     441             :     "label(name: zero_ordered_int_worked)\n"
     442             : 
     443             :     // >, >=, !=, true, ordered
     444             :     "set_variable(name: my_var, value: 7.3)\n"
     445             :     "if(variable: my_var, greater: positive_greater_flt_worked)\n"
     446             :     "exit(error_message: \"if(variable: <positive floating point> + greater) failed test.\")\n"
     447             :     "label(name: positive_greater_flt_worked)\n"
     448             :     "if(variable: my_var, greater_or_equal: positive_greater_or_equal_flt_worked)\n"
     449             :     "exit(error_message: \"if(variable: <positive floating point> + greater_or_equal) failed test.\")\n"
     450             :     "label(name: positive_greater_or_equal_flt_worked)\n"
     451             :     "if(variable: my_var, not_equal: positive_not_equal_flt_worked)\n"
     452             :     "exit(error_message: \"if(variable: <positive floating point> + not_equal) failed test.\")\n"
     453             :     "label(name: positive_not_equal_flt_worked)\n"
     454             :     "if(variable: my_var, true: positive_true_flt_worked)\n"
     455             :     "exit(error_message: \"if(variable: <positive floating point> + true) failed test.\")\n"
     456             :     "label(name: positive_true_flt_worked)\n"
     457             :     "if(variable: my_var, ordered: positive_ordered_flt_worked)\n"
     458             :     "exit(error_message: \"if(variable: <positive floating point> + ordered) failed test.\")\n"
     459             :     "label(name: positive_ordered_flt_worked)\n"
     460             : 
     461             :     // <, <=, !=, true, ordered
     462             :     "set_variable(name: my_var, value: -7.3)\n"
     463             :     "if(variable: my_var, less: negative_less_flt_worked)\n"
     464             :     "exit(error_message: \"if(variable: <negative floating point> + less) failed test.\")\n"
     465             :     "label(name: negative_less_flt_worked)\n"
     466             :     "if(variable: my_var, less_or_equal: negative_less_or_equal_flt_worked)\n"
     467             :     "exit(error_message: \"if(variable: <negative integer> + less_or_equal) failed test.\")\n"
     468             :     "label(name: negative_less_or_equal_flt_worked)\n"
     469             :     "if(variable: my_var, not_equal: negative_not_equal_flt_worked)\n"
     470             :     "exit(error_message: \"if(variable: <negative integer> + not_equal) failed test.\")\n"
     471             :     "label(name: negative_not_equal_flt_worked)\n"
     472             :     "if(variable: my_var, true: negative_true_flt_worked)\n"
     473             :     "exit(error_message: \"if(variable: <negative integer> + true) failed test.\")\n"
     474             :     "label(name: negative_true_flt_worked)\n"
     475             :     "if(variable: my_var, ordered: negative_ordered_flt_worked)\n"
     476             :     "exit(error_message: \"if(variable: <negative integer> + ordered) failed test.\")\n"
     477             :     "label(name: negative_ordered_flt_worked)\n"
     478             : 
     479             :     // ==, false, ordered
     480             :     "set_variable(name: my_var, value: 0.0)\n"
     481             :     "if(variable: my_var, equal: zero_equal_flt_worked)\n"
     482             :     "exit(error_message: \"if(variable: <zero floating point> + equal) failed test.\")\n"
     483             :     "label(name: zero_equal_flt_worked)\n"
     484             :     "if(variable: my_var, less_or_equal: zero_less_or_equal_flt_worked)\n"
     485             :     "exit(error_message: \"if(variable: <negative integer> + less_or_equal) failed test.\")\n"
     486             :     "label(name: zero_less_or_equal_flt_worked)\n"
     487             :     "if(variable: my_var, greater_or_equal: zero_greater_or_equal_flt_worked)\n"
     488             :     "exit(error_message: \"if(variable: <negative integer> + greater_or_equal) failed test.\")\n"
     489             :     "label(name: zero_greater_or_equal_flt_worked)\n"
     490             :     "if(variable: my_var, false: zero_false_flt_worked)\n"
     491             :     "exit(error_message: \"if(variable: <negative integer> + false) failed test.\")\n"
     492             :     "label(name: zero_false_flt_worked)\n"
     493             :     "if(variable: my_var, ordered: zero_ordered_flt_worked)\n"
     494             :     "exit(error_message: \"if(variable: <negative integer> + ordered) failed test.\")\n"
     495             :     "label(name: zero_ordered_flt_worked)\n"
     496             : 
     497             :     // unordered
     498             :     "set_variable(name: my_var, value: NaN)\n"
     499             :     "if(variable: my_var, unordered: unordered_flt_worked)\n"
     500             :     "exit(error_message: \"if(variable: <unordered floating point>) failed test.\")\n"
     501             :     "label(name: unordered_flt_worked)\n"
     502             : 
     503             :     "exit()\n"
     504             : ;
     505             : 
     506             : constexpr char const * const g_program_print_message =
     507             :     "print(message: \"testing print()\")\n"
     508             :     "exit()\n"
     509             : ;
     510             : 
     511             : constexpr char const * const g_program_error_message =
     512             :     "exit(error_message: \"testing exit with an error\")\n"
     513             : ;
     514             : 
     515             : constexpr char const * const g_program_no_condition =
     516             :     "if(true: exit)\n"
     517             :     "label(name: exit)\n"
     518             : ;
     519             : 
     520             : constexpr char const * const g_program_two_listen =
     521             :     "listen(address: <127.0.0.1:20002>)\n"
     522             :     "listen(address: <127.0.0.1:20003>)\n"
     523             : ;
     524             : 
     525             : constexpr char const * const g_program_label_bad_type =
     526             :     "label(name: 123)\n"
     527             : ;
     528             : 
     529             : constexpr char const * const g_program_exit_bad_type =
     530             :     "exit(error_message: 12.3)\n"
     531             : ;
     532             : 
     533             : constexpr char const * const g_program_unsupported_addition_address_address =
     534             :     "set_variable(name: bad, value: <127.0.0.1:80> + <127.0.1.5:81>)\n"
     535             : ;
     536             : 
     537             : constexpr char const * const g_program_unsupported_addition_address_string =
     538             :     "set_variable(name: bad, value: <127.0.0.1:80> + '127.0.1.5:81')\n"
     539             : ;
     540             : 
     541             : constexpr char const * const g_program_unsupported_addition_string_address =
     542             :     "set_variable(name: bad, value: '127.0.0.1:80' + <127.0.1.5:81>)\n"
     543             : ;
     544             : 
     545             : constexpr char const * const g_program_unsupported_addition_address_identifier =
     546             :     "set_variable(name: bad, value: <127.0.0.1:80> + alpha)\n"
     547             : ;
     548             : 
     549             : constexpr char const * const g_program_unsupported_addition_identifier_address =
     550             :     "set_variable(name: bad, value: beta + <127.0.1.5:81>)\n"
     551             : ;
     552             : 
     553             : constexpr char const * const g_program_unsupported_addition_identifier_string =
     554             :     "set_variable(name: bad, value: this + '127.0.1.5:81')\n"
     555             : ;
     556             : 
     557             : constexpr char const * const g_program_unsupported_addition_string_identifier =
     558             :     "set_variable(name: bad, value: '127.0.0.1:80' + that)\n"
     559             : ;
     560             : 
     561             : constexpr char const * const g_program_unsupported_subtraction_address_string =
     562             :     "set_variable(name: bad, value: <127.0.0.1:80> - '127.0.1.5:81')\n"
     563             : ;
     564             : 
     565             : constexpr char const * const g_program_unsupported_subtraction_string_address =
     566             :     "set_variable(name: bad, value: '127.0.0.1:80' - <127.0.1.5:81>)\n"
     567             : ;
     568             : 
     569             : constexpr char const * const g_program_unsupported_subtraction_address_identifier =
     570             :     "set_variable(name: bad, value: <127.0.0.1:80> - alpha)\n"
     571             : ;
     572             : 
     573             : constexpr char const * const g_program_unsupported_subtraction_identifier_address =
     574             :     "set_variable(name: bad, value: beta - <127.0.1.5:81>)\n"
     575             : ;
     576             : 
     577             : constexpr char const * const g_program_unsupported_subtraction_identifier_string =
     578             :     "set_variable(name: bad, value: this - '127.0.1.5:81')\n"
     579             : ;
     580             : 
     581             : constexpr char const * const g_program_unsupported_subtraction_string_identifier =
     582             :     "set_variable(name: bad, value: '127.0.0.1:80' - that)\n"
     583             : ;
     584             : 
     585             : constexpr char const * const g_program_unsupported_multiplication_address_address =
     586             :     "set_variable(name: bad, value: <127.0.0.1:80> * <192.168.2.2:443>)\n"
     587             : ;
     588             : 
     589             : constexpr char const * const g_program_unsupported_multiplication_address_string =
     590             :     "set_variable(name: bad, value: <127.0.0.1:80> * 'invalid')\n"
     591             : ;
     592             : 
     593             : constexpr char const * const g_program_unsupported_multiplication_string_address =
     594             :     "set_variable(name: bad, value: 'invalid' * <127.0.0.1:80>)\n"
     595             : ;
     596             : 
     597             : constexpr char const * const g_program_unsupported_multiplication_address_identifier =
     598             :     "set_variable(name: bad, value: <127.0.0.1:80> * invalid)\n"
     599             : ;
     600             : 
     601             : constexpr char const * const g_program_unsupported_multiplication_identifier_address =
     602             :     "set_variable(name: bad, value: invalid * <127.0.0.1:80>)\n"
     603             : ;
     604             : 
     605             : constexpr char const * const g_program_unsupported_multiplication_identifier_string =
     606             :     "set_variable(name: bad, value: 'invalid' * invalid)\n"
     607             : ;
     608             : 
     609             : constexpr char const * const g_program_unsupported_multiplication_string_identifier =
     610             :     "set_variable(name: bad, value: invalid * \"invalid\")\n"
     611             : ;
     612             : 
     613             : constexpr char const * const g_program_unsupported_multiplication_string_string =
     614             :     "set_variable(name: bad, value: 'invalid' * \"invalid\")\n"
     615             : ;
     616             : 
     617             : constexpr char const * const g_program_unsupported_multiplication_identifier_identifier =
     618             :     "set_variable(name: bad, value: invalid * not_valid)\n"
     619             : ;
     620             : 
     621             : constexpr char const * const g_program_unsupported_division_address_address =
     622             :     "set_variable(name: bad, value: <127.0.0.1:80> / <192.168.2.2:443>)\n"
     623             : ;
     624             : 
     625             : constexpr char const * const g_program_unsupported_division_address_string =
     626             :     "set_variable(name: bad, value: <127.0.0.1:80> / 'invalid')\n"
     627             : ;
     628             : 
     629             : constexpr char const * const g_program_unsupported_division_string_address =
     630             :     "set_variable(name: bad, value: 'invalid' / <127.0.0.1:80>)\n"
     631             : ;
     632             : 
     633             : constexpr char const * const g_program_unsupported_division_address_identifier =
     634             :     "set_variable(name: bad, value: <127.0.0.1:80> / invalid)\n"
     635             : ;
     636             : 
     637             : constexpr char const * const g_program_unsupported_division_identifier_address =
     638             :     "set_variable(name: bad, value: invalid / <127.0.0.1:80>)\n"
     639             : ;
     640             : 
     641             : constexpr char const * const g_program_unsupported_division_identifier_string =
     642             :     "set_variable(name: bad, value: 'invalid' / invalid)\n"
     643             : ;
     644             : 
     645             : constexpr char const * const g_program_unsupported_division_string_identifier =
     646             :     "set_variable(name: bad, value: invalid / \"invalid\")\n"
     647             : ;
     648             : 
     649             : constexpr char const * const g_program_unsupported_division_string_string =
     650             :     "set_variable(name: bad, value: 'invalid' / \"invalid\")\n"
     651             : ;
     652             : 
     653             : constexpr char const * const g_program_unsupported_division_identifier_identifier =
     654             :     "set_variable(name: bad, value: invalid / not_valid)\n"
     655             : ;
     656             : 
     657             : constexpr char const * const g_program_unsupported_modulo_address_address =
     658             :     "set_variable(name: bad, value: <127.0.0.1:80> % <192.168.2.2:443>)\n"
     659             : ;
     660             : 
     661             : constexpr char const * const g_program_unsupported_modulo_address_string =
     662             :     "set_variable(name: bad, value: <127.0.0.1:80> % 'invalid')\n"
     663             : ;
     664             : 
     665             : constexpr char const * const g_program_unsupported_modulo_string_address =
     666             :     "set_variable(name: bad, value: 'invalid' % <127.0.0.1:80>)\n"
     667             : ;
     668             : 
     669             : constexpr char const * const g_program_unsupported_modulo_address_identifier =
     670             :     "set_variable(name: bad, value: <127.0.0.1:80> % invalid)\n"
     671             : ;
     672             : 
     673             : constexpr char const * const g_program_unsupported_modulo_identifier_address =
     674             :     "set_variable(name: bad, value: invalid % <127.0.0.1:80>)\n"
     675             : ;
     676             : 
     677             : constexpr char const * const g_program_unsupported_modulo_identifier_string =
     678             :     "set_variable(name: bad, value: invalid % \"invalid\")\n"
     679             : ;
     680             : 
     681             : constexpr char const * const g_program_unsupported_modulo_string_identifier =
     682             :     "set_variable(name: bad, value: 'invalid' % invalid)\n"
     683             : ;
     684             : 
     685             : constexpr char const * const g_program_unsupported_modulo_string_string =
     686             :     "set_variable(name: bad, value: 'invalid' % \"invalid\")\n"
     687             : ;
     688             : 
     689             : constexpr char const * const g_program_unsupported_modulo_identifier_identifier =
     690             :     "set_variable(name: bad, value: invalid % not_valid)\n"
     691             : ;
     692             : 
     693             : constexpr char const * const g_program_unsupported_negation_single_string =
     694             :     "set_variable(name: bad, value: -'string')\n"
     695             : ;
     696             : 
     697             : constexpr char const * const g_program_unsupported_negation_double_string =
     698             :     "set_variable(name: bad, value: -\"string\")\n"
     699             : ;
     700             : 
     701             : constexpr char const * const g_program_unsupported_negation_address =
     702             :     "set_variable(name: bad, value: -<127.0.0.1:80>)\n"
     703             : ;
     704             : 
     705             : constexpr char const * const g_program_unterminated_double_string_variable =
     706             :     "set_variable(name: my_var, value: \"blah\")\n"
     707             :     "set_variable(name: missing_close, value: \"ref. ${my_var\")\n"
     708             : ;
     709             : 
     710             : constexpr char const * const g_program_regex_in_double_string_variable =
     711             :     "set_variable(name: my_regex, value: `[a-z]+`)\n"
     712             :     "set_variable(name: missing_close, value: \"ref. ${my_regex}\")\n"
     713             : ;
     714             : 
     715             : constexpr char const * const g_program_primary_variable_references =
     716             :     "set_variable(name: my_string_var, value: \"foo\")\n"
     717             :     "set_variable(name: longer_string_var, value: ${my_string_var})\n"
     718             :     "set_variable(name: my_integer_var, value: 41)\n"
     719             :     "set_variable(name: longer_integer_var, value: ${my_integer_var})\n"
     720             :     "set_variable(name: my_floating_point_var, value: 303.601)\n"
     721             :     "set_variable(name: longer_floating_point_var, value: ${my_floating_point_var})\n"
     722             :     "set_variable(name: my_identifier_var, value: bar)\n"
     723             :     "set_variable(name: longer_identifier_var, value: ${my_identifier_var})\n"
     724             :     "set_variable(name: my_regex_var, value: `^[regex]$`)\n"
     725             :     "set_variable(name: longer_regex_var, value: ${my_regex_var})\n"
     726             :     "set_variable(name: my_address_var, value: <10.12.14.16:89>)\n"
     727             :     "set_variable(name: longer_address_var, value: ${my_address_var})\n"
     728             :     "set_variable(name: my_timestamp_var, value: @1714241733.419438123)\n"
     729             :     "set_variable(name: longer_timestamp_var, value: ${my_timestamp_var})\n"
     730             : ;
     731             : 
     732             : constexpr char const * const g_program_wrong_primary_variable_reference =
     733             :     "set_variable(name: my_var, value: foo)\n"
     734             :     "set_variable(name: longer_var, value: ${wrong_name})\n"
     735             : ;
     736             : 
     737             : constexpr char const * const g_program_double_string_variable_without_name =
     738             :     "set_variable(name: missing_close, value: \"ref. ${} is empty\")\n"
     739             : ;
     740             : 
     741             : constexpr char const * const g_program_unsupported_negation_repeat =
     742             :     "set_variable(name: bad, value: 'string' * -5)\n"
     743             : ;
     744             : 
     745             : constexpr char const * const g_program_unsupported_large_repeat =
     746             :     "set_variable(name: bad, value: 'string' * 1001)\n"
     747             : ;
     748             : 
     749             : constexpr char const * const g_program_bad_exit =
     750             :     "exit(error_message: \"bad error occurred!\", timeout: 3.001)\n"
     751             : ;
     752             : 
     753             : constexpr char const * const g_program_bad_exit_timeout =
     754             :     "exit(timeout: 'bad')\n"
     755             : ;
     756             : 
     757             : constexpr char const * const g_program_bad_print_message =
     758             :     "print(message: string_expected)\n"
     759             : ;
     760             : 
     761             : constexpr char const * const g_program_send_message_without_connection =
     762             :     "send_message(command: WITHOUT_CONNECTION)\n"
     763             : ;
     764             : 
     765             : constexpr char const * const g_program_if_invalid_type =
     766             :     "set_variable(name: my_str, value: \"bad\")\n"
     767             :     "if(variable: my_str, unordered: unused)\n"
     768             :     "exit(error_message: \"if() did not fail.\")\n"
     769             :     "label(name: unused)\n"
     770             :     "exit(error_message: \"if() branched unexpectendly.\")\n"
     771             : ;
     772             : 
     773             : constexpr char const * const g_program_wait_outside_thread =
     774             :     "wait(timeout: 10)\n"
     775             : ;
     776             : 
     777             : constexpr char const * const g_program_wait_invalid_mode =
     778             :     "run()\n"
     779             :     "wait(timeout: 10, mode: not_this_one)\n"
     780             : ;
     781             : 
     782             : constexpr char const * const g_program_wait_no_connections =
     783             :     "run()\n"
     784             :     "wait(timeout: 10, mode: wait)\n"
     785             : ;
     786             : 
     787             : constexpr char const * const g_program_verify_message_fail_sent_server =
     788             :     "run()\n"
     789             :     "listen(address: <127.0.0.1:20002>)\n"
     790             :     "label(name: wait_message)\n"
     791             :     "clear_message()\n"
     792             :     "wait(timeout: 12, mode: wait)\n"
     793             :     "has_message()\n"
     794             :     "if(false: wait_message)\n"
     795             :     "show_message()\n"
     796             :     "verify_message(command: REGISTER, sent_server: not_this_one)\n"
     797             :     "exit()\n"
     798             : ;
     799             : 
     800             : constexpr char const * const g_program_verify_message_fail_sent_service =
     801             :     "run()\n"
     802             :     "listen(address: <127.0.0.1:20002>)\n"
     803             :     "label(name: wait_message)\n"
     804             :     "clear_message()\n"
     805             :     "wait(timeout: 12, mode: wait)\n"
     806             :     "has_message()\n"
     807             :     "if(false: wait_message)\n"
     808             :     "show_message()\n"
     809             :     "verify_message(command: REGISTER, sent_service: not_this_one)\n"
     810             :     "exit()\n"
     811             : ;
     812             : 
     813             : constexpr char const * const g_program_verify_message_fail_server =
     814             :     "run()\n"
     815             :     "listen(address: <127.0.0.1:20002>)\n"
     816             :     "label(name: wait_message)\n"
     817             :     "clear_message()\n"
     818             :     "wait(timeout: 12, mode: wait)\n"
     819             :     "has_message()\n"
     820             :     "if(false: wait_message)\n"
     821             :     "show_message()\n"
     822             :     "verify_message(command: REGISTER, server: not_this_one)\n"
     823             :     "exit()\n"
     824             : ;
     825             : 
     826             : constexpr char const * const g_program_verify_message_fail_service =
     827             :     "run()\n"
     828             :     "listen(address: <127.0.0.1:20002>)\n"
     829             :     "label(name: wait_message)\n"
     830             :     "clear_message()\n"
     831             :     "wait(timeout: 12, mode: wait)\n"
     832             :     "has_message()\n"
     833             :     "if(false: wait_message)\n"
     834             :     "show_message()\n"
     835             :     "verify_message(command: REGISTER, service: not_this_one)\n"
     836             :     "exit()\n"
     837             : ;
     838             : 
     839             : constexpr char const * const g_program_verify_message_fail_command =
     840             :     "run()\n"
     841             :     "listen(address: <127.0.0.1:20002>)\n"
     842             :     "label(name: wait_message)\n"
     843             :     "clear_message()\n"
     844             :     "wait(timeout: 12, mode: wait)\n"
     845             :     "has_message()\n"
     846             :     "if(false: wait_message)\n"
     847             :     "show_message()\n"
     848             :     "verify_message(command: NOT_THIS_ONE)\n"
     849             :     "exit()\n"
     850             : ;
     851             : 
     852             : constexpr char const * const g_program_verify_message_fail_forbidden =
     853             :     "run()\n"
     854             :     "listen(address: <127.0.0.1:20002>)\n"
     855             :     "label(name: wait_message)\n"
     856             :     "clear_message()\n"
     857             :     "wait(timeout: 12, mode: wait)\n"
     858             :     "has_message()\n"
     859             :     "if(false: wait_message)\n"
     860             :     "show_message()\n"
     861             :     "verify_message(command: REGISTER, forbidden_parameters: { version })\n"
     862             :     "exit()\n"
     863             : ;
     864             : 
     865             : constexpr char const * const g_program_verify_message_fail_required =
     866             :     "run()\n"
     867             :     "listen(address: <127.0.0.1:20002>)\n"
     868             :     "label(name: wait_message)\n"
     869             :     "clear_message()\n"
     870             :     "wait(timeout: 12, mode: wait)\n"
     871             :     "has_message()\n"
     872             :     "if(false: wait_message)\n"
     873             :     "show_message()\n"
     874             :     "verify_message(command: REGISTER, required_parameters: { not_this_one: 123 })\n"
     875             :     "exit()\n"
     876             : ;
     877             : 
     878             : constexpr char const * const g_program_verify_message_fail_required_int_value =
     879             :     "run()\n"
     880             :     "listen(address: <127.0.0.1:20002>)\n"
     881             :     "label(name: wait_message)\n"
     882             :     "clear_message()\n"
     883             :     "wait(timeout: 12, mode: wait)\n"
     884             :     "has_message()\n"
     885             :     "if(false: wait_message)\n"
     886             :     "show_message()\n"
     887             :     "verify_message(command: REGISTER, required_parameters: { version: 200 })\n"
     888             :     "exit()\n"
     889             : ;
     890             : 
     891             : constexpr char const * const g_program_verify_message_fail_required_str_value =
     892             :     "run()\n"
     893             :     "listen(address: <127.0.0.1:20002>)\n"
     894             :     "label(name: wait_message)\n"
     895             :     "clear_message()\n"
     896             :     "wait(timeout: 12, mode: wait)\n"
     897             :     "has_message()\n"
     898             :     "if(false: wait_message)\n"
     899             :     "show_message()\n"
     900             :     "verify_message(command: REGISTER, required_parameters: { service: not_this_one })\n"
     901             :     "exit()\n"
     902             : ;
     903             : 
     904             : constexpr char const * const g_program_verify_message_fail_required_flt_value =
     905             :     "run()\n"
     906             :     "listen(address: <127.0.0.1:20002>)\n"
     907             :     "label(name: wait_message)\n"
     908             :     "clear_message()\n"
     909             :     "wait(timeout: 12, mode: wait)\n"
     910             :     "has_message()\n"
     911             :     "if(false: wait_message)\n"
     912             :     "show_message()\n"
     913             :     "verify_message(command: REGISTER, required_parameters: { version: 1.0 })\n"
     914             :     "exit()\n"
     915             : ;
     916             : 
     917             : constexpr char const * const g_program_last_wait =
     918             :     "run()\n"
     919             :     "listen(address: <127.0.0.1:20002>)\n"
     920             :     "label(name: wait_message)\n"
     921             :     "clear_message()\n"
     922             :     "wait(timeout: 10.0, mode: wait)\n"
     923             :     "has_message()\n"
     924             :     "if(false: wait_message)\n"
     925             :     "show_message()\n"
     926             :     "verify_message(command: REGISTER, required_parameters: { service: responder, version: 1 }, optional_parameters: { commands: \"READY,HELP,STOP\" }, forbidden_parameters: { forbidden })\n"
     927             :     "send_message(command: READY, sent_server: reporter_test_extension, sent_service: test_processor, server: reporter_test, service: accept_one_message, parameters: { status: alive })\n"
     928             :     "wait(timeout: 1.0, mode: drain)\n" // hope that send_message() is small enough that a single wait is sufficient to send it
     929             :     "wait(timeout: 1.0)\n"
     930             :     "disconnect()\n"
     931             :     "exit()\n"
     932             : ;
     933             : 
     934             : constexpr char const * const g_program_regex_parameter_no_match =
     935             :     "run()\n"
     936             :     "listen(address: <127.0.0.1:20002>)\n"
     937             :     "label(name: wait_message)\n"
     938             :     "clear_message()\n"
     939             :     "wait(timeout: 10.0, mode: wait)\n"
     940             :     "has_message()\n"
     941             :     "if(false: wait_message)\n"
     942             :     "show_message()\n"
     943             :     "verify_message(command: REGISTER, required_parameters: { service: responder, version: `_[a-z]+` }, optional_parameters: { commands: \"READY,HELP,STOP\" }, forbidden_parameters: { forbidden })\n"
     944             :     "send_message(command: READY, sent_server: reporter_test_extension, sent_service: test_processor, server: reporter_test, service: accept_one_message, parameters: { status: alive })\n"
     945             :     "wait(timeout: 1.0, mode: drain)\n"
     946             :     "wait(timeout: 1.0)\n"
     947             :     "disconnect()\n"
     948             :     "exit()\n"
     949             : ;
     950             : 
     951             : constexpr char const * const g_program_wait_for_nothing =
     952             :     "run()\n"
     953             :     "listen(address: <127.0.0.1:20002>)\n"
     954             :     "label(name: wait_message)\n"
     955             :     "clear_message()\n"
     956             :     "wait(timeout: 10.0, mode: wait)\n" // first wait reacts on connect(), second wait receives the REGISTER message
     957             :     "has_message()\n"
     958             :     "if(false: wait_message)\n"
     959             :     "show_message()\n"
     960             :     "verify_message(command: REGISTER, required_parameters: { service: responder, version: 1 }, optional_parameters: { commands: \"READY,HELP,STOP\" }, forbidden_parameters: { forbidden })\n"
     961             :     "send_message(command: READY, sent_server: reporter_test_extension, sent_service: test_processor, server: reporter_test, service: accept_one_message, parameters: { status: alive })\n"
     962             :     "wait(timeout: 1.0, mode: drain)\n"
     963             :     "wait(timeout: 1.0)\n"
     964             :     "wait(timeout: 1.0)\n" // one too many wait(), it will time out
     965             :     "exit()\n"
     966             : ;
     967             : 
     968             : constexpr char const * const g_program_wait_for_timeout =
     969             :     "run()\n"
     970             :     "listen(address: <127.0.0.1:20002>)\n"
     971             :     "label(name: wait_message)\n"
     972             :     "clear_message()\n"
     973             :     "wait(timeout: 10.0, mode: wait)\n" // first wait reacts on connect(), second wait receives the REGISTER message
     974             :     "has_message()\n"
     975             :     "if(false: wait_message)\n"
     976             :     "show_message()\n"
     977             :     "verify_message(command: REGISTER, required_parameters: { service: responder, version: 1 }, optional_parameters: { commands: \"READY,HELP,STOP\" }, forbidden_parameters: { forbidden })\n"
     978             :     "send_message(command: READY, sent_server: reporter_test_extension, sent_service: test_processor, server: reporter_test, service: accept_one_message, parameters: { status: alive })\n"
     979             :     "wait(timeout: 1.0, mode: drain)\n"
     980             :     "wait(timeout: 1.0)\n"
     981             :     "wait(timeout: 1.0, mode: timeout)\n" // one extra wait(), which will time out
     982             :     "exit()\n"
     983             : ;
     984             : 
     985             : 
     986             : 
     987             : struct expected_trace_t
     988             : {
     989             :     SNAP_CATCH2_NAMESPACE::reporter::callback_reason_t const
     990             :                         f_reason = SNAP_CATCH2_NAMESPACE::reporter::callback_reason_t::CALLBACK_REASON_BEFORE_CALL;
     991             :     char const * const  f_name = nullptr;
     992             : };
     993             : 
     994             : 
     995             : constexpr expected_trace_t const g_verify_starting_thread[] =
     996             : {
     997             :     {
     998             :         .f_reason = SNAP_CATCH2_NAMESPACE::reporter::callback_reason_t::CALLBACK_REASON_BEFORE_CALL,
     999             :         .f_name = "set_variable",
    1000             :     },
    1001             :     {
    1002             :         .f_reason = SNAP_CATCH2_NAMESPACE::reporter::callback_reason_t::CALLBACK_REASON_AFTER_CALL,
    1003             :         .f_name = "set_variable",
    1004             :     },
    1005             :     {
    1006             :         .f_reason = SNAP_CATCH2_NAMESPACE::reporter::callback_reason_t::CALLBACK_REASON_BEFORE_CALL,
    1007             :         .f_name = "set_variable",
    1008             :     },
    1009             :     {
    1010             :         .f_reason = SNAP_CATCH2_NAMESPACE::reporter::callback_reason_t::CALLBACK_REASON_AFTER_CALL,
    1011             :         .f_name = "set_variable",
    1012             :     },
    1013             :     {
    1014             :         .f_reason = SNAP_CATCH2_NAMESPACE::reporter::callback_reason_t::CALLBACK_REASON_BEFORE_CALL,
    1015             :         .f_name = "run",
    1016             :     },
    1017             :     {
    1018             :         .f_reason = SNAP_CATCH2_NAMESPACE::reporter::callback_reason_t::CALLBACK_REASON_AFTER_CALL,
    1019             :         .f_name = "run",
    1020             :     },
    1021             :     {
    1022             :         .f_reason = SNAP_CATCH2_NAMESPACE::reporter::callback_reason_t::CALLBACK_REASON_BEFORE_CALL,
    1023             :         .f_name = "set_variable",
    1024             :     },
    1025             :     {
    1026             :         .f_reason = SNAP_CATCH2_NAMESPACE::reporter::callback_reason_t::CALLBACK_REASON_AFTER_CALL,
    1027             :         .f_name = "set_variable",
    1028             :     },
    1029             :     {
    1030             :         .f_reason = SNAP_CATCH2_NAMESPACE::reporter::callback_reason_t::CALLBACK_REASON_BEFORE_CALL,
    1031             :         .f_name = "set_variable",
    1032             :     },
    1033             :     {
    1034             :         .f_reason = SNAP_CATCH2_NAMESPACE::reporter::callback_reason_t::CALLBACK_REASON_AFTER_CALL,
    1035             :         .f_name = "set_variable",
    1036             :     },
    1037             :     {
    1038             :         .f_reason = SNAP_CATCH2_NAMESPACE::reporter::callback_reason_t::CALLBACK_REASON_BEFORE_CALL,
    1039             :         .f_name = "set_variable",
    1040             :     },
    1041             :     {
    1042             :         .f_reason = SNAP_CATCH2_NAMESPACE::reporter::callback_reason_t::CALLBACK_REASON_AFTER_CALL,
    1043             :         .f_name = "set_variable",
    1044             :     },
    1045             :     {
    1046             :         .f_reason = SNAP_CATCH2_NAMESPACE::reporter::callback_reason_t::CALLBACK_REASON_BEFORE_CALL,
    1047             :         .f_name = "set_variable",
    1048             :     },
    1049             :     {
    1050             :         .f_reason = SNAP_CATCH2_NAMESPACE::reporter::callback_reason_t::CALLBACK_REASON_AFTER_CALL,
    1051             :         .f_name = "set_variable",
    1052             :     },
    1053             :     {
    1054             :         .f_reason = SNAP_CATCH2_NAMESPACE::reporter::callback_reason_t::CALLBACK_REASON_BEFORE_CALL,
    1055             :         .f_name = "set_variable",
    1056             :     },
    1057             :     {
    1058             :         .f_reason = SNAP_CATCH2_NAMESPACE::reporter::callback_reason_t::CALLBACK_REASON_AFTER_CALL,
    1059             :         .f_name = "set_variable",
    1060             :     },
    1061             :     {
    1062             :         .f_reason = SNAP_CATCH2_NAMESPACE::reporter::callback_reason_t::CALLBACK_REASON_BEFORE_CALL,
    1063             :         .f_name = "set_variable",
    1064             :     },
    1065             :     {
    1066             :         .f_reason = SNAP_CATCH2_NAMESPACE::reporter::callback_reason_t::CALLBACK_REASON_AFTER_CALL,
    1067             :         .f_name = "set_variable",
    1068             :     },
    1069             :     {
    1070             :         .f_reason = SNAP_CATCH2_NAMESPACE::reporter::callback_reason_t::CALLBACK_REASON_BEFORE_CALL,
    1071             :         .f_name = "set_variable",
    1072             :     },
    1073             :     {
    1074             :         .f_reason = SNAP_CATCH2_NAMESPACE::reporter::callback_reason_t::CALLBACK_REASON_AFTER_CALL,
    1075             :         .f_name = "set_variable",
    1076             :     },
    1077             :     {}
    1078             : };
    1079             : 
    1080             : 
    1081             : class trace
    1082             : {
    1083             : public:
    1084           1 :     trace(expected_trace_t const * expected_trace)
    1085           1 :         : f_expected_trace(expected_trace)
    1086             :     {
    1087           1 :     }
    1088             : 
    1089             :     trace(trace const &) = delete;
    1090             : 
    1091           1 :     ~trace()
    1092             :     {
    1093             :         // make sure we reached the end of the list
    1094             :         //
    1095           1 :         CATCH_REQUIRE(f_expected_trace[f_pos].f_name == nullptr);
    1096           1 :     }
    1097             : 
    1098             :     trace operator = (trace const &) = delete;
    1099             : 
    1100          20 :     void callback(SNAP_CATCH2_NAMESPACE::reporter::state & s, SNAP_CATCH2_NAMESPACE::reporter::callback_reason_t reason)
    1101             :     {
    1102             :         // here we can be in the thread so DO NOT USE CATCH_... macros
    1103             :         //
    1104          20 :         if(f_expected_trace[f_pos].f_name == nullptr)
    1105             :         {
    1106           0 :             throw std::runtime_error(
    1107             :                   "got more calls ("
    1108           0 :                 + std::to_string(f_pos + 1)
    1109           0 :                 + ") to tracer than expected.");
    1110             :         }
    1111             : 
    1112          20 :         if(f_expected_trace[f_pos].f_reason != reason)
    1113             :         {
    1114           0 :             throw std::runtime_error(
    1115             :                   "unexpected reason at position "
    1116           0 :                 + std::to_string(f_pos)
    1117           0 :                 + " (got "
    1118           0 :                 + std::to_string(static_cast<int>(reason))
    1119           0 :                 + ", expected "
    1120           0 :                 + std::to_string(static_cast<int>(f_expected_trace[f_pos].f_reason))
    1121           0 :                 + ").");
    1122             :         }
    1123             : 
    1124          20 :         SNAP_CATCH2_NAMESPACE::reporter::statement::pointer_t stmt(s.get_running_statement());
    1125          20 :         std::string const & name(stmt->get_instruction()->get_name());
    1126             : //std::cerr << "--------------------- at pos " << f_pos << " found reason " << static_cast<int>(reason) << " + name " << name << "\n";
    1127          20 :         if(f_expected_trace[f_pos].f_name != name)
    1128             :         {
    1129           0 :             throw std::runtime_error(
    1130             :                   "unexpected instruction at position "
    1131           0 :                 + std::to_string(f_pos)
    1132           0 :                 + " (got "
    1133           0 :                 + name
    1134           0 :                 + ", expected "
    1135           0 :                 + f_expected_trace[f_pos].f_name
    1136           0 :                 + ").");
    1137             :         }
    1138             : 
    1139          20 :         ++f_pos;
    1140          40 :     }
    1141             : 
    1142             : private:
    1143             :     int                         f_pos = 0;
    1144             :     expected_trace_t const *    f_expected_trace = nullptr;
    1145             : };
    1146             : 
    1147             : 
    1148             : class messenger_responder // an equivalent to a client
    1149             :     : public ed::tcp_client_permanent_message_connection
    1150             : {
    1151             : public:
    1152             :     typedef std::shared_ptr<messenger_responder> pointer_t;
    1153             : 
    1154             :     enum class sequence_t
    1155             :     {
    1156             :         SEQUENCE_ONE_MESSAGE,
    1157             :         SEQUENCE_UNWANTED_MESSAGE,
    1158             :         SEQUENCE_TIMED_MESSAGE,
    1159             :         SEQUENCE_READY_HELP_MESSAGE,
    1160             :         SEQUENCE_READY_THROW,
    1161             :         SEQUENCE_READY_THROW_WHAT,
    1162             :     };
    1163             : 
    1164          24 :     messenger_responder(
    1165             :               addr::addr const & a
    1166             :             , ed::mode_t mode
    1167             :             , sequence_t sequence)
    1168          24 :         : tcp_client_permanent_message_connection(
    1169             :               a
    1170             :             , mode
    1171             :             , ed::DEFAULT_PAUSE_BEFORE_RECONNECTING
    1172             :             , true
    1173             :             , "responder")  // service name
    1174          24 :         , f_sequence(sequence)
    1175             :     {
    1176          24 :         set_name("messenger_responder");    // connection name
    1177          24 :     }
    1178             : 
    1179          23 :     virtual void process_connected() override
    1180             :     {
    1181             :         // always register at the time we connect
    1182             :         //
    1183          23 :         tcp_client_permanent_message_connection::process_connected();
    1184          23 :         register_service();
    1185          23 :     }
    1186             : 
    1187          12 :     virtual void process_message(ed::message & msg) override
    1188             :     {
    1189          12 :         ++f_step;
    1190             :         std::cout
    1191          12 :             << "--- \"client\" message ("
    1192             :             << f_step
    1193             :             << "): "
    1194          12 :             << msg
    1195          12 :             << std::endl;
    1196             : 
    1197          12 :         bool disconnect_all(false);
    1198             : 
    1199          12 :         if(f_step == 1)
    1200             :         {
    1201           8 :             if(msg.get_command() != "READY")
    1202             :             {
    1203           0 :                 throw std::runtime_error(
    1204             :                       "first message expected to be READY, got "
    1205           0 :                     + msg.get_command()
    1206           0 :                     + " instead.");
    1207             :             }
    1208           8 :             if(msg.has_parameter("version"))
    1209             :             {
    1210             :                 // there are cases where I put a version as an integer
    1211             :                 //
    1212           1 :                 std::int64_t version(msg.get_integer_parameter("version"));
    1213           1 :                 if(version != 9)
    1214             :                 {
    1215           0 :                     throw std::runtime_error(
    1216             :                           "READY version value invalid; expected 9, got "
    1217           0 :                         + std::to_string(version)
    1218           0 :                         + " instead.");
    1219             :                 }
    1220             :             }
    1221           8 :             if(msg.has_parameter("date"))
    1222             :             {
    1223             :                 // there are cases where I put a date as a timespec_ex (a timestamp in the language)
    1224             :                 //
    1225           1 :                 snapdev::timespec_ex date(msg.get_timespec_parameter("date"));
    1226           1 :                 if(date != snapdev::timespec_ex(1715440881, 543723981))
    1227             :                 {
    1228           0 :                     throw std::runtime_error(
    1229             :                           "READY date value invalid; expected 1715440881.543723981, got "
    1230           0 :                         + date.to_timestamp()
    1231           0 :                         + " instead.");
    1232             :                 }
    1233             :             }
    1234             :         }
    1235             : 
    1236          12 :         switch(f_sequence)
    1237             :         {
    1238           4 :         case sequence_t::SEQUENCE_ONE_MESSAGE:
    1239           4 :             disconnect_all = true;
    1240           4 :             break;
    1241             : 
    1242           0 :         case sequence_t::SEQUENCE_UNWANTED_MESSAGE:
    1243             :             {
    1244           0 :                 ed::message unwanted;
    1245           0 :                 unwanted.reply_to(msg);
    1246           0 :                 unwanted.set_command("UNWANTED");
    1247           0 :                 unwanted.add_parameter("serial", 7209);
    1248           0 :                 if(!send_message(unwanted, false))
    1249             :                 {
    1250           0 :                     throw std::runtime_error("could not send UNWANTED message");
    1251             :                 }
    1252           0 :             }
    1253             :             break;
    1254             : 
    1255           1 :         case sequence_t::SEQUENCE_TIMED_MESSAGE:
    1256             :             {
    1257           1 :                 ed::message unwanted;
    1258           1 :                 unwanted.reply_to(msg);
    1259           1 :                 unwanted.set_command("TIMED");
    1260           1 :                 unwanted.add_parameter("now", snapdev::now());
    1261           1 :                 if(!send_message(unwanted, false))
    1262             :                 {
    1263           0 :                     throw std::runtime_error("could not send TIMED message");
    1264             :                 }
    1265           1 :             }
    1266             :             break;
    1267             : 
    1268           3 :         case sequence_t::SEQUENCE_READY_HELP_MESSAGE:
    1269           3 :             switch(f_step)
    1270             :             {
    1271           1 :             case 1:
    1272             :                 // done in this case
    1273           1 :                 break;
    1274             : 
    1275           1 :             case 2:
    1276           1 :                 if(msg.get_command() != "HELP")
    1277             :                 {
    1278           0 :                     throw std::runtime_error(
    1279             :                           "second message expected to be HELP, got "
    1280           0 :                         + msg.get_command()
    1281           0 :                         + " instead.");
    1282             :                 }
    1283             : 
    1284             :                 {
    1285           1 :                     ed::message commands;
    1286           1 :                     commands.reply_to(msg);
    1287           1 :                     commands.set_sent_from_server("reporter_test");
    1288           1 :                     commands.set_sent_from_service("commands_message");
    1289           1 :                     commands.set_command("COMMANDS");
    1290           1 :                     commands.add_parameter("list", "HELP,READY,STOP");
    1291             : //std::cerr << "--- respond with COMMANDS\n";
    1292           1 :                     if(!send_message(commands, false))
    1293             :                     {
    1294           0 :                         throw std::runtime_error("could not send COMMANDS message");
    1295             :                     }
    1296           1 :                 }
    1297             :                 break;
    1298             : 
    1299           1 :             case 3:
    1300           1 :                 if(msg.get_command() != "STOP")
    1301             :                 {
    1302           0 :                     throw std::runtime_error(
    1303             :                           "third message expected to be STOP, got "
    1304           0 :                         + msg.get_command()
    1305           0 :                         + " instead.");
    1306             :                 }
    1307             : 
    1308           1 :                 disconnect_all = true;
    1309           1 :                 break;
    1310             : 
    1311           0 :             default:
    1312           0 :                 throw std::runtime_error("reached step 4 of SEQUENCE_READY_HELP_MESSAGE?");
    1313             : 
    1314             :             }
    1315           3 :             break;
    1316             : 
    1317           2 :         case sequence_t::SEQUENCE_READY_THROW:
    1318           2 :             switch(f_step)
    1319             :             {
    1320           1 :             case 1:
    1321             :                 // done in this case
    1322           1 :                 break;
    1323             : 
    1324           1 :             case 2:
    1325           1 :                 if(msg.get_command() != "HELP")
    1326             :                 {
    1327           0 :                     throw std::runtime_error(
    1328             :                           "second message expected to be HELP, got "
    1329           0 :                         + msg.get_command()
    1330           0 :                         + " instead.");
    1331             :                 }
    1332             : 
    1333             :                 // got the help message, now do a "legitimate" throw
    1334             :                 //
    1335           1 :                 throw std::runtime_error("testing that the executor catches these exceptions.");
    1336             : 
    1337           0 :             default:
    1338           0 :                 throw std::runtime_error("reached step 4 of SEQUENCE_READY_THROW?");
    1339             : 
    1340             :             }
    1341           1 :             break;
    1342             : 
    1343           2 :         case sequence_t::SEQUENCE_READY_THROW_WHAT:
    1344           2 :             switch(f_step)
    1345             :             {
    1346           1 :             case 1:
    1347             :                 // done in this case
    1348           1 :                 break;
    1349             : 
    1350           1 :             case 2:
    1351           1 :                 if(msg.get_command() != "HELP")
    1352             :                 {
    1353           0 :                     throw std::runtime_error(
    1354             :                           "second message expected to be HELP, got "
    1355           0 :                         + msg.get_command()
    1356           0 :                         + " instead.");
    1357             :                 }
    1358             : 
    1359             :                 // got the help message, now do a "legitimate" throw
    1360             :                 //
    1361             :                 struct my_exception
    1362             :                 {
    1363             :                     int code = 0;
    1364             :                 };
    1365           1 :                 throw my_exception({5});
    1366             : 
    1367           0 :             default:
    1368           0 :                 throw std::runtime_error("reached step 4 of SEQUENCE_READY_THROW_WHAT?");
    1369             : 
    1370             :             }
    1371           1 :             break;
    1372             : 
    1373             :         }
    1374             : 
    1375          10 :         if(disconnect_all)
    1376             :         {
    1377           5 :             remove_from_communicator();
    1378             : 
    1379           5 :             ed::connection::pointer_t timer_ptr(f_timer.lock());
    1380           5 :             if(timer_ptr != nullptr)
    1381             :             {
    1382           5 :                 timer_ptr->remove_from_communicator();
    1383             :             }
    1384           5 :         }
    1385          10 :     }
    1386             : 
    1387          19 :     void set_timer(ed::connection::pointer_t done_timer)
    1388             :     {
    1389          19 :         f_timer = done_timer;
    1390          19 :     }
    1391             : 
    1392             : private:
    1393             :     // the sequence & step define the next action
    1394             :     //
    1395             :     sequence_t  f_sequence = sequence_t::SEQUENCE_ONE_MESSAGE;
    1396             :     int         f_step = 0;
    1397             :     ed::connection::weak_pointer_t
    1398             :                 f_timer = ed::connection::weak_pointer_t();
    1399             : };
    1400             : 
    1401             : 
    1402             : class messenger_timer
    1403             :     : public ed::timer
    1404             : {
    1405             : public:
    1406             :     typedef std::shared_ptr<messenger_timer>        pointer_t;
    1407             : 
    1408          19 :     messenger_timer(messenger_responder::pointer_t m)
    1409          19 :         : timer(10'000'000)
    1410          19 :         , f_messenger(m)
    1411             :     {
    1412          19 :         set_name("messenger_timer");
    1413          19 :     }
    1414             : 
    1415           2 :     void process_timeout()
    1416             :     {
    1417             :         // call default function(s)
    1418             :         //
    1419           2 :         timer::process_timeout();
    1420             : 
    1421           2 :         remove_from_communicator();
    1422           2 :         f_messenger->remove_from_communicator();
    1423           2 :         f_timed_out = true;
    1424           2 :     }
    1425             : 
    1426          19 :     bool timed_out_prima() const
    1427             :     {
    1428          19 :         return f_timed_out;
    1429             :     }
    1430             : 
    1431             : private:
    1432             :     messenger_responder::pointer_t      f_messenger = messenger_responder::pointer_t();
    1433             :     bool                                f_timed_out = false;
    1434             : };
    1435             : 
    1436             : 
    1437             : 
    1438             : 
    1439             : 
    1440             : 
    1441             : } // no name namespace
    1442             : 
    1443             : 
    1444             : 
    1445          11 : CATCH_TEST_CASE("reporter_executor", "[executor][reporter]")
    1446             : {
    1447          11 :     CATCH_START_SECTION("verify sleep in a function")
    1448             :     {
    1449           1 :         SNAP_CATCH2_NAMESPACE::reporter::lexer::pointer_t l(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::lexer>("program_sleep_func.rprtr", g_program_sleep_func));
    1450           1 :         SNAP_CATCH2_NAMESPACE::reporter::state::pointer_t s(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::state>());
    1451           1 :         SNAP_CATCH2_NAMESPACE::reporter::parser::pointer_t p(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::parser>(l, s));
    1452           1 :         p->parse_program();
    1453             : 
    1454           1 :         CATCH_REQUIRE(s->get_statement_size() == 5);
    1455             : 
    1456           1 :         SNAP_CATCH2_NAMESPACE::reporter::executor::pointer_t e(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::executor>(s));
    1457           1 :         snapdev::timespec_ex const start(snapdev::now());
    1458           1 :         e->start();
    1459           1 :         CATCH_REQUIRE(e->run());
    1460           1 :         snapdev::timespec_ex end(snapdev::now());
    1461           1 :         end -= start;
    1462           1 :         CATCH_REQUIRE(end.tv_sec >= 2); // we slept for 2.5 seconds, so we expect at least start + 2 seconds
    1463           1 :     }
    1464          11 :     CATCH_END_SECTION()
    1465             : 
    1466          11 :     CATCH_START_SECTION("verify starting the thread")
    1467             :     {
    1468           1 :         trace tracer(g_verify_starting_thread);
    1469             : 
    1470           1 :         SNAP_CATCH2_NAMESPACE::reporter::lexer::pointer_t l(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::lexer>("program_start_thread.rprtr", g_program_start_thread));
    1471           1 :         SNAP_CATCH2_NAMESPACE::reporter::state::pointer_t s(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::state>());
    1472             : 
    1473             :         // use std::bind() to avoid copies of the tracer object
    1474             :         //
    1475           1 :         s->set_trace_callback(std::bind(&trace::callback, &tracer, std::placeholders::_1, std::placeholders::_2));
    1476             : 
    1477           1 :         SNAP_CATCH2_NAMESPACE::reporter::parser::pointer_t p(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::parser>(l, s));
    1478           1 :         p->parse_program();
    1479             : 
    1480           1 :         CATCH_REQUIRE(s->get_statement_size() == 10);
    1481             : 
    1482             :         // before we run the script, there are no such variables
    1483             :         //
    1484           3 :         SNAP_CATCH2_NAMESPACE::reporter::variable::pointer_t var(s->get_variable("test"));
    1485           1 :         CATCH_REQUIRE(var == nullptr);
    1486           1 :         var = s->get_variable("test_copy_between_dollars");
    1487           1 :         CATCH_REQUIRE(var == nullptr);
    1488           1 :         var = s->get_variable("runner");
    1489           1 :         CATCH_REQUIRE(var == nullptr);
    1490           1 :         var = s->get_variable("runner_copy_as_is");
    1491           1 :         CATCH_REQUIRE(var == nullptr);
    1492           1 :         var = s->get_variable("time_limit");
    1493           1 :         CATCH_REQUIRE(var == nullptr);
    1494           1 :         var = s->get_variable("time_limit_copy");
    1495           1 :         CATCH_REQUIRE(var == nullptr);
    1496           1 :         var = s->get_variable("host_ip");
    1497           1 :         CATCH_REQUIRE(var == nullptr);
    1498           1 :         var = s->get_variable("host_ip_copy");
    1499           1 :         CATCH_REQUIRE(var == nullptr);
    1500           1 :         var = s->get_variable("time_and_host_ip");
    1501           1 :         CATCH_REQUIRE(var == nullptr);
    1502             : 
    1503           1 :         SNAP_CATCH2_NAMESPACE::reporter::executor::pointer_t e(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::executor>(s));
    1504           1 :         e->start();
    1505           1 :         CATCH_REQUIRE(e->run());
    1506             : 
    1507           1 :         var = s->get_variable("test");
    1508           1 :         CATCH_REQUIRE(var != nullptr);
    1509           1 :         CATCH_REQUIRE(var->get_name() == "test");
    1510           1 :         CATCH_REQUIRE(var->get_type() == "integer");
    1511           1 :         CATCH_REQUIRE(std::static_pointer_cast<SNAP_CATCH2_NAMESPACE::reporter::variable_integer>(var)->get_integer() == 33);
    1512             : 
    1513           1 :         var = s->get_variable("test_copy_between_dollars");
    1514           1 :         CATCH_REQUIRE(var != nullptr);
    1515           1 :         CATCH_REQUIRE(var->get_name() == "test_copy_between_dollars");
    1516           1 :         CATCH_REQUIRE(var->get_type() == "string");
    1517           1 :         CATCH_REQUIRE(std::static_pointer_cast<SNAP_CATCH2_NAMESPACE::reporter::variable_string>(var)->get_string() == "$33$");
    1518             : 
    1519           1 :         var = s->get_variable("runner");
    1520           1 :         CATCH_REQUIRE(var != nullptr);
    1521           1 :         CATCH_REQUIRE(var->get_name() == "runner");
    1522           1 :         CATCH_REQUIRE(var->get_type() == "floating_point");
    1523           1 :         CATCH_REQUIRE(std::static_pointer_cast<SNAP_CATCH2_NAMESPACE::reporter::variable_floating_point>(var)->get_floating_point() == 6.07);
    1524             : 
    1525           1 :         var = s->get_variable("runner_copy_as_is");
    1526           1 :         CATCH_REQUIRE(var != nullptr);
    1527           1 :         CATCH_REQUIRE(var->get_name() == "runner_copy_as_is");
    1528           1 :         CATCH_REQUIRE(var->get_type() == "string");
    1529           1 :         CATCH_REQUIRE(std::static_pointer_cast<SNAP_CATCH2_NAMESPACE::reporter::variable_string>(var)->get_string() == "runner = 6.07");
    1530             : 
    1531           1 :         var = s->get_variable("time_limit");
    1532           1 :         CATCH_REQUIRE(var != nullptr);
    1533           1 :         CATCH_REQUIRE(var->get_name() == "time_limit");
    1534           1 :         CATCH_REQUIRE(var->get_type() == "timestamp");
    1535           1 :         snapdev::timespec_ex const time_limit(1713934141, 107805991);
    1536           1 :         CATCH_REQUIRE(std::static_pointer_cast<SNAP_CATCH2_NAMESPACE::reporter::variable_timestamp>(var)->get_timestamp() == time_limit);
    1537             : 
    1538           1 :         var = s->get_variable("time_limit_copy");
    1539           1 :         CATCH_REQUIRE(var != nullptr);
    1540           1 :         CATCH_REQUIRE(var->get_name() == "time_limit_copy");
    1541           1 :         CATCH_REQUIRE(var->get_type() == "string");
    1542           1 :         CATCH_REQUIRE(std::static_pointer_cast<SNAP_CATCH2_NAMESPACE::reporter::variable_string>(var)->get_string() == "limit: 1713934141.107805991");
    1543             : 
    1544           1 :         var = s->get_variable("host_ip");
    1545           1 :         CATCH_REQUIRE(var != nullptr);
    1546           1 :         CATCH_REQUIRE(var->get_name() == "host_ip");
    1547           1 :         CATCH_REQUIRE(var->get_type() == "address");
    1548           1 :         addr::addr a;
    1549           1 :         sockaddr_in ip = {
    1550             :             .sin_family = AF_INET,
    1551           1 :             .sin_port = htons(0),
    1552             :             .sin_addr = {
    1553           1 :                 .s_addr = htonl(0x7f070333),
    1554             :             },
    1555             :             .sin_zero = {},
    1556           1 :         };
    1557           1 :         a.set_ipv4(ip);
    1558           1 :         CATCH_REQUIRE(std::static_pointer_cast<SNAP_CATCH2_NAMESPACE::reporter::variable_address>(var)->get_address() == a);
    1559             : 
    1560           1 :         var = s->get_variable("host_ip_copy");
    1561           1 :         CATCH_REQUIRE(var != nullptr);
    1562           1 :         CATCH_REQUIRE(var->get_name() == "host_ip_copy");
    1563           1 :         CATCH_REQUIRE(var->get_type() == "string");
    1564           1 :         CATCH_REQUIRE(std::static_pointer_cast<SNAP_CATCH2_NAMESPACE::reporter::variable_string>(var)->get_string() == "Host is at 127.7.3.51 address");
    1565             : 
    1566           1 :         var = s->get_variable("time_and_host_ip");
    1567           1 :         CATCH_REQUIRE(var != nullptr);
    1568           1 :         CATCH_REQUIRE(var->get_name() == "time_and_host_ip");
    1569           1 :         CATCH_REQUIRE(var->get_type() == "string");
    1570           1 :         CATCH_REQUIRE(std::static_pointer_cast<SNAP_CATCH2_NAMESPACE::reporter::variable_string>(var)->get_string() == "time 1713934141.107805991 and address 127.7.3.51...");
    1571           1 :     }
    1572          11 :     CATCH_END_SECTION()
    1573             : 
    1574          11 :     CATCH_START_SECTION("verify computation (integers)")
    1575             :     {
    1576           1 :         SNAP_CATCH2_NAMESPACE::reporter::lexer::pointer_t l(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::lexer>("verify_computation_integer.rprtr", g_program_verify_computation_integer));
    1577           1 :         SNAP_CATCH2_NAMESPACE::reporter::state::pointer_t s(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::state>());
    1578           1 :         SNAP_CATCH2_NAMESPACE::reporter::parser::pointer_t p(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::parser>(l, s));
    1579           1 :         p->parse_program();
    1580             : 
    1581           1 :         CATCH_REQUIRE(s->get_statement_size() == 15);
    1582             : 
    1583           1 :         SNAP_CATCH2_NAMESPACE::reporter::executor::pointer_t e(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::executor>(s));
    1584           1 :         e->start();
    1585           1 :         CATCH_REQUIRE(e->run());
    1586             : 
    1587           1 :         SNAP_CATCH2_NAMESPACE::reporter::variable::pointer_t var;
    1588             : 
    1589           1 :         var = s->get_variable("t01");
    1590           1 :         CATCH_REQUIRE(var != nullptr);
    1591           1 :         CATCH_REQUIRE(var->get_name() == "t01");
    1592           1 :         CATCH_REQUIRE(var->get_type() == "integer");
    1593           1 :         CATCH_REQUIRE(std::static_pointer_cast<SNAP_CATCH2_NAMESPACE::reporter::variable_integer>(var)->get_integer() == 3);
    1594             : 
    1595           1 :         var = s->get_variable("t11");
    1596           1 :         CATCH_REQUIRE(var != nullptr);
    1597           1 :         CATCH_REQUIRE(var->get_name() == "t11");
    1598           1 :         CATCH_REQUIRE(var->get_type() == "integer");
    1599           1 :         CATCH_REQUIRE(std::static_pointer_cast<SNAP_CATCH2_NAMESPACE::reporter::variable_integer>(var)->get_integer() == -3);
    1600             : 
    1601           1 :         var = s->get_variable("t12");
    1602           1 :         CATCH_REQUIRE(var != nullptr);
    1603           1 :         CATCH_REQUIRE(var->get_name() == "t12");
    1604           1 :         CATCH_REQUIRE(var->get_type() == "integer");
    1605           1 :         CATCH_REQUIRE(std::static_pointer_cast<SNAP_CATCH2_NAMESPACE::reporter::variable_integer>(var)->get_integer() == +3);
    1606             : 
    1607           1 :         var = s->get_variable("t21");
    1608           1 :         CATCH_REQUIRE(var != nullptr);
    1609           1 :         CATCH_REQUIRE(var->get_name() == "t21");
    1610           1 :         CATCH_REQUIRE(var->get_type() == "integer");
    1611           1 :         CATCH_REQUIRE(std::static_pointer_cast<SNAP_CATCH2_NAMESPACE::reporter::variable_integer>(var)->get_integer() == 3 + 2);
    1612             : 
    1613           1 :         var = s->get_variable("t22");
    1614           1 :         CATCH_REQUIRE(var != nullptr);
    1615           1 :         CATCH_REQUIRE(var->get_name() == "t22");
    1616           1 :         CATCH_REQUIRE(var->get_type() == "integer");
    1617           1 :         CATCH_REQUIRE(std::static_pointer_cast<SNAP_CATCH2_NAMESPACE::reporter::variable_integer>(var)->get_integer() == -(3 + 2));
    1618             : 
    1619           1 :         var = s->get_variable("t23");
    1620           1 :         CATCH_REQUIRE(var != nullptr);
    1621           1 :         CATCH_REQUIRE(var->get_name() == "t23");
    1622           1 :         CATCH_REQUIRE(var->get_type() == "integer");
    1623           1 :         CATCH_REQUIRE(std::static_pointer_cast<SNAP_CATCH2_NAMESPACE::reporter::variable_integer>(var)->get_integer() == 20 - 4);
    1624             : 
    1625           1 :         var = s->get_variable("t24");
    1626           1 :         CATCH_REQUIRE(var != nullptr);
    1627           1 :         CATCH_REQUIRE(var->get_name() == "t24");
    1628           1 :         CATCH_REQUIRE(var->get_type() == "integer");
    1629           1 :         CATCH_REQUIRE(std::static_pointer_cast<SNAP_CATCH2_NAMESPACE::reporter::variable_integer>(var)->get_integer() == 3 * 2);
    1630             : 
    1631           1 :         var = s->get_variable("t25");
    1632           1 :         CATCH_REQUIRE(var != nullptr);
    1633           1 :         CATCH_REQUIRE(var->get_name() == "t25");
    1634           1 :         CATCH_REQUIRE(var->get_type() == "integer");
    1635           1 :         CATCH_REQUIRE(std::static_pointer_cast<SNAP_CATCH2_NAMESPACE::reporter::variable_integer>(var)->get_integer() == 20 / 4);
    1636             : 
    1637           1 :         var = s->get_variable("t26");
    1638           1 :         CATCH_REQUIRE(var != nullptr);
    1639           1 :         CATCH_REQUIRE(var->get_name() == "t26");
    1640           1 :         CATCH_REQUIRE(var->get_type() == "integer");
    1641           1 :         CATCH_REQUIRE(std::static_pointer_cast<SNAP_CATCH2_NAMESPACE::reporter::variable_integer>(var)->get_integer() == 27 % 11);
    1642             : 
    1643           1 :         var = s->get_variable("t31");
    1644           1 :         CATCH_REQUIRE(var != nullptr);
    1645           1 :         CATCH_REQUIRE(var->get_name() == "t31");
    1646           1 :         CATCH_REQUIRE(var->get_type() == "integer");
    1647           1 :         CATCH_REQUIRE(std::static_pointer_cast<SNAP_CATCH2_NAMESPACE::reporter::variable_integer>(var)->get_integer() == 3 + 2 * 5);
    1648             : 
    1649           1 :         var = s->get_variable("t32");
    1650           1 :         CATCH_REQUIRE(var != nullptr);
    1651           1 :         CATCH_REQUIRE(var->get_name() == "t32");
    1652           1 :         CATCH_REQUIRE(var->get_type() == "integer");
    1653           1 :         CATCH_REQUIRE(std::static_pointer_cast<SNAP_CATCH2_NAMESPACE::reporter::variable_integer>(var)->get_integer() == -7 + 15 / 3);
    1654             : 
    1655           1 :         var = s->get_variable("t33");
    1656           1 :         CATCH_REQUIRE(var != nullptr);
    1657           1 :         CATCH_REQUIRE(var->get_name() == "t33");
    1658           1 :         CATCH_REQUIRE(var->get_type() == "integer");
    1659           1 :         CATCH_REQUIRE(std::static_pointer_cast<SNAP_CATCH2_NAMESPACE::reporter::variable_integer>(var)->get_integer() == +2 + 15 % 7);
    1660             : 
    1661           1 :         var = s->get_variable("t41");
    1662           1 :         CATCH_REQUIRE(var != nullptr);
    1663           1 :         CATCH_REQUIRE(var->get_name() == "t41");
    1664           1 :         CATCH_REQUIRE(var->get_type() == "integer");
    1665           1 :         CATCH_REQUIRE(std::static_pointer_cast<SNAP_CATCH2_NAMESPACE::reporter::variable_integer>(var)->get_integer() == (3 + 2) * 5);
    1666             : 
    1667           1 :         var = s->get_variable("t42");
    1668           1 :         CATCH_REQUIRE(var != nullptr);
    1669           1 :         CATCH_REQUIRE(var->get_name() == "t42");
    1670           1 :         CATCH_REQUIRE(var->get_type() == "integer");
    1671           1 :         CATCH_REQUIRE(std::static_pointer_cast<SNAP_CATCH2_NAMESPACE::reporter::variable_integer>(var)->get_integer() == (-7 + 15) / 3);
    1672             : 
    1673           1 :         var = s->get_variable("t43");
    1674           1 :         CATCH_REQUIRE(var != nullptr);
    1675           1 :         CATCH_REQUIRE(var->get_name() == "t43");
    1676           1 :         CATCH_REQUIRE(var->get_type() == "integer");
    1677           1 :         CATCH_REQUIRE(std::static_pointer_cast<SNAP_CATCH2_NAMESPACE::reporter::variable_integer>(var)->get_integer() == (+2 + 15) % 7);
    1678           1 :     }
    1679          11 :     CATCH_END_SECTION()
    1680             : 
    1681          11 :     CATCH_START_SECTION("verify computation (floating points)")
    1682             :     {
    1683           1 :         SNAP_CATCH2_NAMESPACE::reporter::lexer::pointer_t l(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::lexer>("verify_computation_floating_point.rprtr", g_program_verify_computation_floating_point));
    1684           1 :         SNAP_CATCH2_NAMESPACE::reporter::state::pointer_t s(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::state>());
    1685           1 :         SNAP_CATCH2_NAMESPACE::reporter::parser::pointer_t p(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::parser>(l, s));
    1686           1 :         p->parse_program();
    1687             : 
    1688           1 :         CATCH_REQUIRE(s->get_statement_size() == 63);
    1689             : 
    1690           1 :         SNAP_CATCH2_NAMESPACE::reporter::executor::pointer_t e(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::executor>(s));
    1691           1 :         e->start();
    1692           1 :         CATCH_REQUIRE(e->run());
    1693             : 
    1694             :         struct verify_t
    1695             :         {
    1696             :             char const *    f_name = nullptr;
    1697             :             double          f_value = 0.0;
    1698             :         };
    1699             : 
    1700           1 :         verify_t verify[] =
    1701             :         {
    1702             :             { "t01", 3.01 },
    1703             :             { "t11", -3.5 },
    1704             :             { "t12", +3.2 },
    1705             :             { "t21ff", 3.01 + 2.45 },
    1706             :             { "t21if", 3 + 2.54 },
    1707             :             { "t21fi", 3.01 + 2 },
    1708             :             { "t22ff", -(3.5 + 2.5) },
    1709             :             { "t22if", -(3 + 2.11) },
    1710             :             { "t22fi", -(3.07 + 2) },
    1711             :             { "t23ff", 20.07 - 4.13 },
    1712             :             { "t23if", 20 - 4.78 },
    1713             :             { "t23fi", 20.91 - 4 },
    1714             :             { "t24ff", 3.41 * 2.14 },
    1715             :             { "t24if", 3 * 2.67 },
    1716             :             { "t24fi", 3.32 * 2 },
    1717             :             { "t25ff", 20.83 / 4.07 },
    1718             :             { "t25if", 20 / 4.4 },
    1719             :             { "t25fi", 20.93 / 4 },
    1720           1 :             { "t26ff", fmod(27.27, 11.11) },
    1721           1 :             { "t26if", fmod(27, 11.88) },
    1722           1 :             { "t26fi", fmod(27.72, 11) },
    1723             :             { "t31fff", 3.03 + 2.2 * 5.9 },
    1724             :             { "t31iff", 3 + 2.5 * 5.7 },
    1725             :             { "t31fif", 3.2 + 2 * 5.3 },
    1726             :             { "t31ffi", 3.07 + 2.28 * 5 },
    1727             :             { "t31iif", 3 + 2 * 5.67 },
    1728             :             { "t31ifi", 3 + 2.56 * 5 },
    1729             :             { "t31fii", 3.33 + 2 * 5 },
    1730             :             { "t32fff", -7.11 + 15.7 / 3.06 },
    1731             :             { "t32iff", -7 + 15.25 / 3.31 },
    1732             :             { "t32fif", -7.78 + 15 / 3.77 },
    1733             :             { "t32ffi", -7.09 + 15.34 / 3 },
    1734             :             { "t32iif", -7 + 15 / 3.30 },
    1735             :             { "t32ifi", -7 + 15.09 / 3 },
    1736             :             { "t32fii", -7.94 + 15 / 3 },
    1737           1 :             { "t33fff", +2.21 + fmod(15.16, 7.8) },
    1738           1 :             { "t33iff", +2 + fmod(15.12, 7.93) },
    1739           1 :             { "t33fif", +2.58 + fmod(15, 7.63) },
    1740           1 :             { "t33ffi", +2.12 + fmod(15.09, 7) },
    1741           1 :             { "t33iif", +2 + fmod(15, 7.19) },
    1742           1 :             { "t33ifi", +2 + fmod(15.18, 7) },
    1743           1 :             { "t33fii", +2.17 + fmod(15, 7) },
    1744             :             { "t41fff", (3.45 + 2.06) * 5.55 },
    1745             :             { "t41iff", (3 + 2.17) * 5.07 },
    1746             :             { "t41fif", (3.37 + 2) * 5.12 },
    1747             :             { "t41ffi", (3.45 + 2.67) * 5 },
    1748             :             { "t41iif", (3 + 2) * 5.3 },
    1749             :             { "t41ifi", (3 + 2.9) * 5 },
    1750             :             { "t41fii", (3.4 + 2) * 5 },
    1751             :             { "t42fff", (-7.4 + 15.15) / 3.93 },
    1752             :             { "t42iff", (-7 + 15.21) / 3.43 },
    1753             :             { "t42fif", (-7.72 + 15) / 3.31 },
    1754             :             { "t42ffi", (-7.43 + 15.89) / 3 },
    1755             :             { "t42iif", (-7 + 15) / 3.4 },
    1756             :             { "t42ifi", (-7 + 15.09) / 3 },
    1757             :             { "t42fii", (-7.73 + 15) / 3 },
    1758           1 :             { "t43fff", fmod((+2.25 + 15.36), 7.47) },
    1759           1 :             { "t43iff", fmod((+2 + 15.16), 7.38) },
    1760           1 :             { "t43fif", fmod((+2.51 + 15), 7.59) },
    1761           1 :             { "t43ffi", fmod((+2.4 + 15.3), 7) },
    1762           1 :             { "t43iif", fmod((+2 + 15), 7.0) },
    1763           1 :             { "t43ifi", fmod((+2 + 15.8), 7) },
    1764           1 :             { "t43fii", fmod((+2.07 + 15), 7) },
    1765           1 :         };
    1766             : 
    1767           1 :         SNAP_CATCH2_NAMESPACE::reporter::variable::pointer_t var;
    1768          64 :         for(auto const & v : verify)
    1769             :         {
    1770             : //std::cerr << "--- testing \"" << v.f_name << "\".\n";
    1771          63 :             var = s->get_variable(v.f_name);
    1772          63 :             CATCH_REQUIRE(var != nullptr);
    1773          63 :             CATCH_REQUIRE(var->get_name() == v.f_name);
    1774          63 :             CATCH_REQUIRE(var->get_type() == "floating_point");
    1775          63 :             CATCH_REQUIRE(std::static_pointer_cast<SNAP_CATCH2_NAMESPACE::reporter::variable_floating_point>(var)->get_floating_point() == v.f_value);
    1776             :         }
    1777           1 :     }
    1778          11 :     CATCH_END_SECTION()
    1779             : 
    1780          11 :     CATCH_START_SECTION("verify computation (timestamp)")
    1781             :     {
    1782           1 :         SNAP_CATCH2_NAMESPACE::reporter::lexer::pointer_t l(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::lexer>("verify_computation_timestamp.rprtr", g_program_verify_computation_timestamp));
    1783           1 :         SNAP_CATCH2_NAMESPACE::reporter::state::pointer_t s(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::state>());
    1784           1 :         SNAP_CATCH2_NAMESPACE::reporter::parser::pointer_t p(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::parser>(l, s));
    1785           1 :         p->parse_program();
    1786             : 
    1787           1 :         CATCH_REQUIRE(s->get_statement_size() == 12);
    1788             : 
    1789           1 :         SNAP_CATCH2_NAMESPACE::reporter::executor::pointer_t e(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::executor>(s));
    1790           1 :         e->start();
    1791           1 :         CATCH_REQUIRE(e->run());
    1792             : 
    1793             :         struct verify_t
    1794             :         {
    1795             :             char const *            f_name = nullptr;
    1796             :             snapdev::timespec_ex    f_value = snapdev::timespec_ex();
    1797             :         };
    1798             : 
    1799           1 :         verify_t verify[] =
    1800             :         {
    1801             :             { "t01", { 123 + 5, 0 } },
    1802             :             { "t02", { 33 + 123, 0 } },
    1803             :             { "t03", { 123 - 5, 0 } },
    1804             :             { "t04", { 33 - 123, 0 } },
    1805             :             { "t11", { 123 + 5, 89'999'999 } },
    1806             :             { "t12", { 33 + 123, 501'923'820 } },
    1807             :             { "t13", { 123 - 6, 999'000'000 } },
    1808             :             { "t14", { 333 - 123, 982'019'920 } },
    1809             :             { "t21", { -123, 0 } },
    1810             :             { "t22", { 123, 0 } },
    1811             :             { "t31", { 177, 330'000'000 } },
    1812             :             { "t32", { 158, 310'731'200 } },
    1813           1 :         };
    1814             : 
    1815           1 :         SNAP_CATCH2_NAMESPACE::reporter::variable::pointer_t var;
    1816          13 :         for(auto const & v : verify)
    1817             :         {
    1818             : //std::cerr << "--- testing \"" << v.f_name << "\".\n";
    1819          12 :             var = s->get_variable(v.f_name);
    1820          12 :             CATCH_REQUIRE(var != nullptr);
    1821          12 :             CATCH_REQUIRE(var->get_name() == v.f_name);
    1822          12 :             CATCH_REQUIRE(var->get_type() == "timestamp");
    1823          12 :             CATCH_REQUIRE(std::static_pointer_cast<SNAP_CATCH2_NAMESPACE::reporter::variable_timestamp>(var)->get_timestamp() == v.f_value);
    1824             :         }
    1825           1 :     }
    1826          11 :     CATCH_END_SECTION()
    1827             : 
    1828          11 :     CATCH_START_SECTION("verify now")
    1829             :     {
    1830           1 :         SNAP_CATCH2_NAMESPACE::reporter::lexer::pointer_t l(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::lexer>("verify_now.rprtr", g_program_verify_now));
    1831           1 :         SNAP_CATCH2_NAMESPACE::reporter::state::pointer_t s(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::state>());
    1832           1 :         SNAP_CATCH2_NAMESPACE::reporter::parser::pointer_t p(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::parser>(l, s));
    1833           1 :         p->parse_program();
    1834             : 
    1835           1 :         CATCH_REQUIRE(s->get_statement_size() == 1);
    1836             : 
    1837           1 :         SNAP_CATCH2_NAMESPACE::reporter::executor::pointer_t e(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::executor>(s));
    1838           1 :         e->start();
    1839           1 :         CATCH_REQUIRE(e->run());
    1840             : 
    1841           1 :         SNAP_CATCH2_NAMESPACE::reporter::variable::pointer_t var;
    1842           1 :         var = s->get_variable("about_now");
    1843           1 :         CATCH_REQUIRE(var != nullptr);
    1844           1 :         CATCH_REQUIRE(var->get_name() == "about_now");
    1845           1 :         CATCH_REQUIRE(var->get_type() == "timestamp");
    1846           1 :         snapdev::timespec_ex const value(std::static_pointer_cast<SNAP_CATCH2_NAMESPACE::reporter::variable_timestamp>(var)->get_timestamp());
    1847           1 :         snapdev::timespec_ex const now(snapdev::now());
    1848           1 :         snapdev::timespec_ex const lower_value(now - snapdev::timespec_ex(1, 0));
    1849           1 :         CATCH_REQUIRE(lower_value <= value);
    1850           1 :         CATCH_REQUIRE(now >= value);
    1851           1 :     }
    1852          11 :     CATCH_END_SECTION()
    1853             : 
    1854          11 :     CATCH_START_SECTION("verify computation (address)")
    1855             :     {
    1856           1 :         SNAP_CATCH2_NAMESPACE::reporter::lexer::pointer_t l(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::lexer>("verify_computation_address.rprtr", g_program_verify_computation_address));
    1857           1 :         SNAP_CATCH2_NAMESPACE::reporter::state::pointer_t s(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::state>());
    1858           1 :         SNAP_CATCH2_NAMESPACE::reporter::parser::pointer_t p(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::parser>(l, s));
    1859           1 :         p->parse_program();
    1860             : 
    1861           1 :         CATCH_REQUIRE(s->get_statement_size() == 4);
    1862             : 
    1863           1 :         SNAP_CATCH2_NAMESPACE::reporter::executor::pointer_t e(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::executor>(s));
    1864           1 :         e->start();
    1865           1 :         CATCH_REQUIRE(e->run());
    1866             : 
    1867             :     //"set_variable(name: t01, value: <127.0.0.1> + 256)\n"
    1868             :     //"set_variable(name: t02, value: 256 + <192.168.3.57>)\n"
    1869             :     //"set_variable(name: t03, value: <172.131.4.1> - 256)\n"
    1870             :     //"set_variable(name: t11, value: <10.5.34.255> - <10.5.33.0>)\n"
    1871             : 
    1872           1 :         SNAP_CATCH2_NAMESPACE::reporter::variable::pointer_t var;
    1873           1 :         addr::addr a;
    1874             : 
    1875           1 :         var = s->get_variable("t01");
    1876           1 :         CATCH_REQUIRE(var != nullptr);
    1877           1 :         CATCH_REQUIRE(var->get_name() == "t01");
    1878           1 :         CATCH_REQUIRE(var->get_type() == "address");
    1879           1 :         a = addr::string_to_addr("127.0.1.1");
    1880           1 :         CATCH_REQUIRE(std::static_pointer_cast<SNAP_CATCH2_NAMESPACE::reporter::variable_address>(var)->get_address() == a);
    1881             : 
    1882           1 :         var = s->get_variable("t02");
    1883           1 :         CATCH_REQUIRE(var != nullptr);
    1884           1 :         CATCH_REQUIRE(var->get_name() == "t02");
    1885           1 :         CATCH_REQUIRE(var->get_type() == "address");
    1886           1 :         a = addr::string_to_addr("192.168.4.57");
    1887           1 :         CATCH_REQUIRE(std::static_pointer_cast<SNAP_CATCH2_NAMESPACE::reporter::variable_address>(var)->get_address() == a);
    1888             : 
    1889           1 :         var = s->get_variable("t03");
    1890           1 :         CATCH_REQUIRE(var != nullptr);
    1891           1 :         CATCH_REQUIRE(var->get_name() == "t03");
    1892           1 :         CATCH_REQUIRE(var->get_type() == "address");
    1893           1 :         a = addr::string_to_addr("172.131.3.1");
    1894           1 :         CATCH_REQUIRE(std::static_pointer_cast<SNAP_CATCH2_NAMESPACE::reporter::variable_address>(var)->get_address() == a);
    1895             : 
    1896           1 :         var = s->get_variable("t11");
    1897           1 :         CATCH_REQUIRE(var != nullptr);
    1898           1 :         CATCH_REQUIRE(var->get_name() == "t11");
    1899           1 :         CATCH_REQUIRE(var->get_type() == "integer");
    1900           1 :         CATCH_REQUIRE(std::static_pointer_cast<SNAP_CATCH2_NAMESPACE::reporter::variable_integer>(var)->get_integer() == 511);
    1901           1 :     }
    1902          11 :     CATCH_END_SECTION()
    1903             : 
    1904          11 :     CATCH_START_SECTION("verify computation (concatenation)")
    1905             :     {
    1906           1 :         SNAP_CATCH2_NAMESPACE::reporter::lexer::pointer_t l(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::lexer>("verify_computation_concatenation.rprtr", g_program_verify_computation_concatenation));
    1907           1 :         SNAP_CATCH2_NAMESPACE::reporter::state::pointer_t s(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::state>());
    1908           1 :         SNAP_CATCH2_NAMESPACE::reporter::parser::pointer_t p(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::parser>(l, s));
    1909           1 :         p->parse_program();
    1910             : 
    1911           1 :         CATCH_REQUIRE(s->get_statement_size() == 12);
    1912             : 
    1913           1 :         SNAP_CATCH2_NAMESPACE::reporter::executor::pointer_t e(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::executor>(s));
    1914           1 :         e->start();
    1915           1 :         CATCH_REQUIRE(e->run());
    1916             : 
    1917             :         struct verify_t
    1918             :         {
    1919             :             char const *            f_name = nullptr;
    1920             :             char const *            f_value = nullptr;
    1921             :             char const *            f_type = nullptr;
    1922             :         };
    1923             : 
    1924           1 :         verify_t verify[] =
    1925             :         {
    1926             :             { "t01", "identifier", "identifier" },
    1927             :             { "t11", "single string", "string" },
    1928             :             { "t12", "single string", "string" },
    1929             :             { "t13", "single string", "string" },
    1930             :             { "t14", "double string", "string" },
    1931             :             { "t21", "identify", "identifier" },
    1932             :             { "t22", "single string", "string" },
    1933             :             { "t23", "double string", "string" },
    1934             :             { "t31", "single36", "string" },
    1935             :             { "t32", "258single", "string" },
    1936             :             { "t33", "string102", "string" },
    1937             :             { "t34", "5005double", "string" },
    1938             :         };
    1939             : 
    1940           1 :         SNAP_CATCH2_NAMESPACE::reporter::variable::pointer_t var;
    1941          13 :         for(auto const & v : verify)
    1942             :         {
    1943             : //std::cerr << "--- testing \"" << v.f_name << "\".\n";
    1944          12 :             var = s->get_variable(v.f_name);
    1945          12 :             CATCH_REQUIRE(var != nullptr);
    1946          12 :             CATCH_REQUIRE(var->get_name() == v.f_name);
    1947          12 :             CATCH_REQUIRE(var->get_type() == v.f_type);
    1948          12 :             CATCH_REQUIRE(std::static_pointer_cast<SNAP_CATCH2_NAMESPACE::reporter::variable_string>(var)->get_string() == v.f_value);
    1949             :         }
    1950           1 :     }
    1951          11 :     CATCH_END_SECTION()
    1952             : 
    1953          11 :     CATCH_START_SECTION("verify computation (string repeat)")
    1954             :     {
    1955           1 :         SNAP_CATCH2_NAMESPACE::reporter::lexer::pointer_t l(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::lexer>("verify_computation_string_repeat.rprtr", g_program_verify_computation_string_repeat));
    1956           1 :         SNAP_CATCH2_NAMESPACE::reporter::state::pointer_t s(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::state>());
    1957           1 :         SNAP_CATCH2_NAMESPACE::reporter::parser::pointer_t p(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::parser>(l, s));
    1958           1 :         p->parse_program();
    1959             : 
    1960           1 :         CATCH_REQUIRE(s->get_statement_size() == 4);
    1961             : 
    1962           1 :         SNAP_CATCH2_NAMESPACE::reporter::executor::pointer_t e(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::executor>(s));
    1963           1 :         e->start();
    1964           1 :         CATCH_REQUIRE(e->run());
    1965             : 
    1966             :         struct verify_t
    1967             :         {
    1968             :             char const *            f_name = nullptr;
    1969             :             char const *            f_value = nullptr;
    1970             :         };
    1971             : 
    1972           1 :         verify_t verify[] =
    1973             :         {
    1974             :             { "t01", "abcabcabc" },
    1975             :             { "t02", "xyzxyzxyzxyzxyz" },
    1976             :             { "t03", "" },
    1977             :             { "t04", "one" },
    1978             :         };
    1979             : 
    1980           1 :         SNAP_CATCH2_NAMESPACE::reporter::variable::pointer_t var;
    1981           5 :         for(auto const & v : verify)
    1982             :         {
    1983             : //std::cerr << "--- testing \"" << v.f_name << "\".\n";
    1984           4 :             var = s->get_variable(v.f_name);
    1985           4 :             CATCH_REQUIRE(var != nullptr);
    1986           4 :             CATCH_REQUIRE(var->get_name() == v.f_name);
    1987           4 :             CATCH_REQUIRE(var->get_type() == "string");
    1988           4 :             CATCH_REQUIRE(std::static_pointer_cast<SNAP_CATCH2_NAMESPACE::reporter::variable_string>(var)->get_string() == v.f_value);
    1989             :         }
    1990           1 :     }
    1991          11 :     CATCH_END_SECTION()
    1992             : 
    1993          11 :     CATCH_START_SECTION("verify variable in string")
    1994             :     {
    1995           1 :         SNAP_CATCH2_NAMESPACE::reporter::lexer::pointer_t l(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::lexer>("verify_variable_in_string.rprtr", g_program_verify_variable_in_string));
    1996           1 :         SNAP_CATCH2_NAMESPACE::reporter::state::pointer_t s(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::state>());
    1997           1 :         SNAP_CATCH2_NAMESPACE::reporter::parser::pointer_t p(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::parser>(l, s));
    1998           1 :         p->parse_program();
    1999             : 
    2000           1 :         CATCH_REQUIRE(s->get_statement_size() == 2);
    2001             : 
    2002           1 :         SNAP_CATCH2_NAMESPACE::reporter::executor::pointer_t e(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::executor>(s));
    2003           1 :         e->start();
    2004           1 :         CATCH_REQUIRE(e->run());
    2005             : 
    2006             :         struct verify_t
    2007             :         {
    2008             :             char const *            f_name = nullptr;
    2009             :             char const *            f_value = nullptr;
    2010             :         };
    2011             : 
    2012           1 :         verify_t verify[] =
    2013             :         {
    2014             :             { "foo", "abc" },
    2015             :             { "bar", "[abc]" },
    2016             :         };
    2017             : 
    2018           1 :         SNAP_CATCH2_NAMESPACE::reporter::variable::pointer_t var;
    2019           3 :         for(auto const & v : verify)
    2020             :         {
    2021             : //std::cerr << "--- testing \"" << v.f_name << "\".\n";
    2022           2 :             var = s->get_variable(v.f_name);
    2023           2 :             CATCH_REQUIRE(var != nullptr);
    2024           2 :             CATCH_REQUIRE(var->get_name() == v.f_name);
    2025           2 :             CATCH_REQUIRE(var->get_type() == "string");
    2026           2 :             CATCH_REQUIRE(std::static_pointer_cast<SNAP_CATCH2_NAMESPACE::reporter::variable_string>(var)->get_string() == v.f_value);
    2027             :         }
    2028           1 :     }
    2029          11 :     CATCH_END_SECTION()
    2030             : 
    2031          11 :     CATCH_START_SECTION("print() + message")
    2032             :     {
    2033           1 :         SNAP_CATCH2_NAMESPACE::reporter::lexer::pointer_t l(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::lexer>("print_message.rprtr.rprtr", g_program_print_message));
    2034           1 :         SNAP_CATCH2_NAMESPACE::reporter::state::pointer_t s(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::state>());
    2035           1 :         SNAP_CATCH2_NAMESPACE::reporter::parser::pointer_t p(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::parser>(l, s));
    2036           1 :         p->parse_program();
    2037             : 
    2038           1 :         CATCH_REQUIRE(s->get_statement_size() == 2);
    2039             : 
    2040           1 :         SNAP_CATCH2_NAMESPACE::reporter::executor::pointer_t e(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::executor>(s));
    2041           1 :         e->start();
    2042             : 
    2043           1 :         CATCH_REQUIRE(s->get_exit_code() == 0);
    2044           1 :     }
    2045          11 :     CATCH_END_SECTION()
    2046          11 : }
    2047             : 
    2048             : 
    2049           9 : CATCH_TEST_CASE("reporter_executor_message", "[executor][reporter]")
    2050             : {
    2051           9 :     CATCH_START_SECTION("send/receive one message")
    2052             :     {
    2053           1 :         SNAP_CATCH2_NAMESPACE::reporter::lexer::pointer_t l(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::lexer>("program_accept_one_message.rprtr", g_program_accept_one_message));
    2054           1 :         SNAP_CATCH2_NAMESPACE::reporter::state::pointer_t s(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::state>());
    2055           1 :         SNAP_CATCH2_NAMESPACE::reporter::parser::pointer_t p(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::parser>(l, s));
    2056           1 :         p->parse_program();
    2057             : 
    2058           1 :         CATCH_REQUIRE(s->get_statement_size() == 15);
    2059             : 
    2060           1 :         SNAP_CATCH2_NAMESPACE::reporter::executor::pointer_t e(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::executor>(s));
    2061           1 :         e->start();
    2062           1 :         addr::addr a;
    2063           1 :         sockaddr_in ip = {
    2064             :             .sin_family = AF_INET,
    2065           1 :             .sin_port = htons(20002),
    2066             :             .sin_addr = {
    2067           1 :                 .s_addr = htonl(0x7f000001),
    2068             :             },
    2069             :             .sin_zero = {},
    2070           1 :         };
    2071           1 :         a.set_ipv4(ip);
    2072           1 :         messenger_responder::pointer_t messenger(std::make_shared<messenger_responder>(
    2073             :                   a
    2074           1 :                 , ed::mode_t::MODE_PLAIN
    2075           2 :                 , messenger_responder::sequence_t::SEQUENCE_ONE_MESSAGE));
    2076           1 :         ed::communicator::instance()->add_connection(messenger);
    2077           1 :         messenger_timer::pointer_t timer(std::make_shared<messenger_timer>(messenger));
    2078           1 :         ed::communicator::instance()->add_connection(timer);
    2079           1 :         messenger->set_timer(timer);
    2080             : 
    2081           1 :         CATCH_REQUIRE(e->run());
    2082             : 
    2083             :         // if we exited because of our timer, then the test did not pass
    2084             :         //
    2085           1 :         CATCH_REQUIRE_FALSE(timer->timed_out_prima());
    2086             : 
    2087           1 :         CATCH_REQUIRE(s->get_exit_code() == 0);
    2088             : 
    2089           3 :         SNAP_CATCH2_NAMESPACE::reporter::variable::pointer_t var(s->get_variable("register_version"));
    2090           1 :         CATCH_REQUIRE(var != nullptr);
    2091           1 :         SNAP_CATCH2_NAMESPACE::reporter::variable_string::pointer_t v(std::dynamic_pointer_cast<SNAP_CATCH2_NAMESPACE::reporter::variable_string>(var));
    2092           1 :         CATCH_REQUIRE(v != nullptr);
    2093           1 :         CATCH_REQUIRE(v->get_string() == "1");
    2094             : 
    2095           1 :         var = s->get_variable("register_service");
    2096           1 :         CATCH_REQUIRE(var != nullptr);
    2097           1 :         v = std::dynamic_pointer_cast<SNAP_CATCH2_NAMESPACE::reporter::variable_string>(var);
    2098           1 :         CATCH_REQUIRE(v != nullptr);
    2099           1 :         CATCH_REQUIRE(v->get_string() == "responder");
    2100           1 :     }
    2101           9 :     CATCH_END_SECTION()
    2102             : 
    2103           9 :     CATCH_START_SECTION("receive one unwanted/unexpected message")
    2104             :     {
    2105           1 :         SNAP_CATCH2_NAMESPACE::reporter::lexer::pointer_t l(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::lexer>("program_receive_unwanted_message.rprtr", g_program_receive_unwanted_message));
    2106           1 :         SNAP_CATCH2_NAMESPACE::reporter::state::pointer_t s(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::state>());
    2107           1 :         SNAP_CATCH2_NAMESPACE::reporter::parser::pointer_t p(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::parser>(l, s));
    2108           1 :         p->parse_program();
    2109             : 
    2110           1 :         CATCH_REQUIRE(s->get_statement_size() == 13);
    2111             : 
    2112           1 :         SNAP_CATCH2_NAMESPACE::reporter::executor::pointer_t e(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::executor>(s));
    2113           1 :         e->start();
    2114           1 :         addr::addr a;
    2115           1 :         sockaddr_in ip = {
    2116             :             .sin_family = AF_INET,
    2117           1 :             .sin_port = htons(20002),
    2118             :             .sin_addr = {
    2119           1 :                 .s_addr = htonl(0x7f000001),
    2120             :             },
    2121             :             .sin_zero = {},
    2122           1 :         };
    2123           1 :         a.set_ipv4(ip);
    2124           1 :         messenger_responder::pointer_t messenger(std::make_shared<messenger_responder>(
    2125             :                   a
    2126           1 :                 , ed::mode_t::MODE_PLAIN
    2127           2 :                 , messenger_responder::sequence_t::SEQUENCE_UNWANTED_MESSAGE));
    2128           1 :         ed::communicator::instance()->add_connection(messenger);
    2129           1 :         e->set_thread_done_callback([messenger]()
    2130             :             {
    2131           1 :                 ed::communicator::instance()->remove_connection(messenger);
    2132           1 :             });
    2133             : 
    2134           1 :         CATCH_REQUIRE(e->run());
    2135             : 
    2136           1 :         CATCH_REQUIRE(s->get_exit_code() == 1);
    2137           1 :     }
    2138           9 :     CATCH_END_SECTION()
    2139             : 
    2140           9 :     CATCH_START_SECTION("send message with unsupported parameter type fails")
    2141             :     {
    2142           1 :         SNAP_CATCH2_NAMESPACE::reporter::lexer::pointer_t l(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::lexer>("program_send_unsupported_message_parameter_type.rprtr", g_program_send_unsupported_message_parameter_type));
    2143           1 :         SNAP_CATCH2_NAMESPACE::reporter::state::pointer_t s(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::state>());
    2144           1 :         SNAP_CATCH2_NAMESPACE::reporter::parser::pointer_t p(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::parser>(l, s));
    2145           1 :         p->parse_program();
    2146             : 
    2147           1 :         CATCH_REQUIRE(s->get_statement_size() == 12);
    2148             : 
    2149           1 :         SNAP_CATCH2_NAMESPACE::reporter::executor::pointer_t e(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::executor>(s));
    2150           1 :         e->start();
    2151           1 :         addr::addr a;
    2152           1 :         sockaddr_in ip = {
    2153             :             .sin_family = AF_INET,
    2154           1 :             .sin_port = htons(20002),
    2155             :             .sin_addr = {
    2156           1 :                 .s_addr = htonl(0x7f000001),
    2157             :             },
    2158             :             .sin_zero = {},
    2159           1 :         };
    2160           1 :         a.set_ipv4(ip);
    2161           1 :         messenger_responder::pointer_t messenger(std::make_shared<messenger_responder>(
    2162             :                   a
    2163           1 :                 , ed::mode_t::MODE_PLAIN
    2164           2 :                 , messenger_responder::sequence_t::SEQUENCE_UNWANTED_MESSAGE));
    2165           1 :         ed::communicator::instance()->add_connection(messenger);
    2166           1 :         e->set_thread_done_callback([messenger]()
    2167             :             {
    2168           1 :                 ed::communicator::instance()->remove_connection(messenger);
    2169           1 :             });
    2170             : 
    2171           1 :         CATCH_REQUIRE(e->run());
    2172           1 :         CATCH_REQUIRE_THROWS_MATCHES(
    2173             :               e->stop()
    2174             :             , std::runtime_error
    2175             :             , Catch::Matchers::ExceptionMessage(
    2176             :                       "message parameter type \"floating_point\" not supported yet."));
    2177             : 
    2178           1 :         CATCH_REQUIRE(s->get_exit_code() == -1);
    2179           1 :     }
    2180           9 :     CATCH_END_SECTION()
    2181             : 
    2182           9 :     CATCH_START_SECTION("save message parameter identifier as an integer fails")
    2183             :     {
    2184           1 :         SNAP_CATCH2_NAMESPACE::reporter::lexer::pointer_t l(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::lexer>("program_send_invalid_parameter_value_type.rprtr", g_program_send_invalid_parameter_value_type));
    2185           1 :         SNAP_CATCH2_NAMESPACE::reporter::state::pointer_t s(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::state>());
    2186           1 :         SNAP_CATCH2_NAMESPACE::reporter::parser::pointer_t p(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::parser>(l, s));
    2187           1 :         p->parse_program();
    2188             : 
    2189           1 :         CATCH_REQUIRE(s->get_statement_size() == 12);
    2190             : 
    2191           1 :         SNAP_CATCH2_NAMESPACE::reporter::executor::pointer_t e(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::executor>(s));
    2192           1 :         e->start();
    2193           1 :         addr::addr a;
    2194           1 :         sockaddr_in ip = {
    2195             :             .sin_family = AF_INET,
    2196           1 :             .sin_port = htons(20002),
    2197             :             .sin_addr = {
    2198           1 :                 .s_addr = htonl(0x7f000001),
    2199             :             },
    2200             :             .sin_zero = {},
    2201           1 :         };
    2202           1 :         a.set_ipv4(ip);
    2203           1 :         messenger_responder::pointer_t messenger(std::make_shared<messenger_responder>(
    2204             :                   a
    2205           1 :                 , ed::mode_t::MODE_PLAIN
    2206           2 :                 , messenger_responder::sequence_t::SEQUENCE_UNWANTED_MESSAGE));
    2207           1 :         ed::communicator::instance()->add_connection(messenger);
    2208           1 :         e->set_thread_done_callback([messenger]()
    2209             :             {
    2210           1 :                 ed::communicator::instance()->remove_connection(messenger);
    2211           1 :             });
    2212             : 
    2213           1 :         CATCH_REQUIRE(e->run());
    2214           1 :         CATCH_REQUIRE_THROWS_MATCHES(
    2215             :               e->stop()
    2216             :             , std::runtime_error
    2217             :             , Catch::Matchers::ExceptionMessage(
    2218             :                       "value \"responder\" not recognized as a valid integer."));
    2219             : 
    2220           1 :         CATCH_REQUIRE(s->get_exit_code() == -1);
    2221           1 :     }
    2222           9 :     CATCH_END_SECTION()
    2223             : 
    2224           9 :     CATCH_START_SECTION("save message parameter of type timestamp")
    2225             :     {
    2226           1 :         SNAP_CATCH2_NAMESPACE::reporter::lexer::pointer_t l(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::lexer>("program_save_parameter_of_type_timestamp.rprtr", g_program_save_parameter_of_type_timestamp));
    2227           1 :         SNAP_CATCH2_NAMESPACE::reporter::state::pointer_t s(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::state>());
    2228           1 :         SNAP_CATCH2_NAMESPACE::reporter::parser::pointer_t p(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::parser>(l, s));
    2229           1 :         p->parse_program();
    2230             : 
    2231             :         //CATCH_REQUIRE(s->get_statement_size() == 19);
    2232             : 
    2233           1 :         SNAP_CATCH2_NAMESPACE::reporter::executor::pointer_t e(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::executor>(s));
    2234           1 :         e->start();
    2235           1 :         addr::addr a;
    2236           1 :         sockaddr_in ip = {
    2237             :             .sin_family = AF_INET,
    2238           1 :             .sin_port = htons(20002),
    2239             :             .sin_addr = {
    2240           1 :                 .s_addr = htonl(0x7f000001),
    2241             :             },
    2242             :             .sin_zero = {},
    2243           1 :         };
    2244           1 :         a.set_ipv4(ip);
    2245           1 :         messenger_responder::pointer_t messenger(std::make_shared<messenger_responder>(
    2246             :                   a
    2247           1 :                 , ed::mode_t::MODE_PLAIN
    2248           2 :                 , messenger_responder::sequence_t::SEQUENCE_TIMED_MESSAGE));
    2249           1 :         ed::communicator::instance()->add_connection(messenger);
    2250           1 :         e->set_thread_done_callback([messenger]()
    2251             :             {
    2252           1 :                 ed::communicator::instance()->remove_connection(messenger);
    2253           1 :             });
    2254             : 
    2255           1 :         CATCH_REQUIRE(e->run());
    2256           1 :         e->stop();
    2257             : 
    2258           1 :         CATCH_REQUIRE(s->get_exit_code() == 0);
    2259             : 
    2260           3 :         SNAP_CATCH2_NAMESPACE::reporter::variable::pointer_t var(s->get_variable("register_version"));
    2261           1 :         CATCH_REQUIRE(var != nullptr);
    2262           1 :         SNAP_CATCH2_NAMESPACE::reporter::variable_integer::pointer_t vi(std::dynamic_pointer_cast<SNAP_CATCH2_NAMESPACE::reporter::variable_integer>(var));
    2263           1 :         CATCH_REQUIRE(vi != nullptr);
    2264           1 :         CATCH_REQUIRE(vi->get_type() == "integer");
    2265           1 :         CATCH_REQUIRE(vi->get_integer() == 1);
    2266             : 
    2267           1 :         var = s->get_variable("default_integer");
    2268           1 :         CATCH_REQUIRE(var != nullptr);
    2269           1 :         vi = std::dynamic_pointer_cast<SNAP_CATCH2_NAMESPACE::reporter::variable_integer>(var);
    2270           1 :         CATCH_REQUIRE(vi != nullptr);
    2271           1 :         CATCH_REQUIRE(vi->get_type() == "integer");
    2272           1 :         CATCH_REQUIRE(vi->get_integer() == 0);
    2273             : 
    2274           1 :         var = s->get_variable("timed_value");
    2275           1 :         CATCH_REQUIRE(var != nullptr);
    2276           1 :         SNAP_CATCH2_NAMESPACE::reporter::variable_timestamp::pointer_t vts(std::dynamic_pointer_cast<SNAP_CATCH2_NAMESPACE::reporter::variable_timestamp>(var));
    2277           1 :         CATCH_REQUIRE(vts != nullptr);
    2278           1 :         CATCH_REQUIRE(vts->get_type() == "timestamp");
    2279           1 :         snapdev::timespec_ex const param_timestamp(vts->get_timestamp());
    2280           1 :         snapdev::timespec_ex const now(snapdev::now());
    2281           1 :         snapdev::timespec_ex const minimum_value(now - snapdev::timespec_ex(1, 0));
    2282           1 :         CATCH_REQUIRE(param_timestamp >= minimum_value);
    2283           1 :         CATCH_REQUIRE(param_timestamp <= now);
    2284             : 
    2285           1 :         var = s->get_variable("default_time");
    2286           1 :         CATCH_REQUIRE(var != nullptr);
    2287           1 :         vts = std::dynamic_pointer_cast<SNAP_CATCH2_NAMESPACE::reporter::variable_timestamp>(var);
    2288           1 :         CATCH_REQUIRE(vts != nullptr);
    2289           1 :         CATCH_REQUIRE(vts->get_type() == "timestamp");
    2290           1 :         CATCH_REQUIRE(vts->get_timestamp() == snapdev::timespec_ex());
    2291           1 :     }
    2292           9 :     CATCH_END_SECTION()
    2293             : 
    2294           9 :     CATCH_START_SECTION("save message parameter with unknown type")
    2295             :     {
    2296           1 :         SNAP_CATCH2_NAMESPACE::reporter::lexer::pointer_t l(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::lexer>("program_save_parameter_with_unknown_type.rprtr", g_program_save_parameter_with_unknown_type));
    2297           1 :         SNAP_CATCH2_NAMESPACE::reporter::state::pointer_t s(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::state>());
    2298           1 :         SNAP_CATCH2_NAMESPACE::reporter::parser::pointer_t p(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::parser>(l, s));
    2299           1 :         p->parse_program();
    2300             : 
    2301           1 :         CATCH_REQUIRE(s->get_statement_size() == 12);
    2302             : 
    2303           1 :         SNAP_CATCH2_NAMESPACE::reporter::executor::pointer_t e(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::executor>(s));
    2304           1 :         e->start();
    2305           1 :         addr::addr a;
    2306           1 :         sockaddr_in ip = {
    2307             :             .sin_family = AF_INET,
    2308           1 :             .sin_port = htons(20002),
    2309             :             .sin_addr = {
    2310           1 :                 .s_addr = htonl(0x7f000001),
    2311             :             },
    2312             :             .sin_zero = {},
    2313           1 :         };
    2314           1 :         a.set_ipv4(ip);
    2315           1 :         messenger_responder::pointer_t messenger(std::make_shared<messenger_responder>(
    2316             :                   a
    2317           1 :                 , ed::mode_t::MODE_PLAIN
    2318           2 :                 , messenger_responder::sequence_t::SEQUENCE_UNWANTED_MESSAGE));
    2319           1 :         ed::communicator::instance()->add_connection(messenger);
    2320           1 :         e->set_thread_done_callback([messenger]()
    2321             :             {
    2322           1 :                 ed::communicator::instance()->remove_connection(messenger);
    2323           1 :             });
    2324             : 
    2325           1 :         CATCH_REQUIRE(e->run());
    2326           1 :         CATCH_REQUIRE_THROWS_MATCHES(
    2327             :               e->stop()
    2328             :             , std::runtime_error
    2329             :             , Catch::Matchers::ExceptionMessage(
    2330             :                       "unsupported type \"void\" for save_parameter_value()."));
    2331             : 
    2332           1 :         CATCH_REQUIRE(s->get_exit_code() == -1);
    2333           1 :     }
    2334           9 :     CATCH_END_SECTION()
    2335             : 
    2336           9 :     CATCH_START_SECTION("send & receive complete messages")
    2337             :     {
    2338             :         // in this case, load the program from a file
    2339             :         // to verify that this works as expected
    2340             :         //
    2341           1 :         std::string const source_dir(SNAP_CATCH2_NAMESPACE::g_source_dir());
    2342           1 :         std::string const filename(source_dir + "/tests/rprtr/send_and_receive_complete_messages");
    2343           1 :         SNAP_CATCH2_NAMESPACE::reporter::lexer::pointer_t l(SNAP_CATCH2_NAMESPACE::reporter::create_lexer(filename));
    2344           1 :         SNAP_CATCH2_NAMESPACE::reporter::state::pointer_t s(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::state>());
    2345           1 :         SNAP_CATCH2_NAMESPACE::reporter::parser::pointer_t p(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::parser>(l, s));
    2346           1 :         p->parse_program();
    2347             : 
    2348           1 :         CATCH_REQUIRE(s->get_statement_size() == 30);
    2349             : 
    2350           1 :         SNAP_CATCH2_NAMESPACE::reporter::executor::pointer_t e(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::executor>(s));
    2351           1 :         e->start();
    2352           1 :         addr::addr a;
    2353           1 :         sockaddr_in ip = {
    2354             :             .sin_family = AF_INET,
    2355           1 :             .sin_port = htons(20002),
    2356             :             .sin_addr = {
    2357           1 :                 .s_addr = htonl(0x7f000001),
    2358             :             },
    2359             :             .sin_zero = {},
    2360           1 :         };
    2361           1 :         a.set_ipv4(ip);
    2362           1 :         messenger_responder::pointer_t messenger(std::make_shared<messenger_responder>(
    2363             :                   a
    2364           1 :                 , ed::mode_t::MODE_PLAIN
    2365           2 :                 , messenger_responder::sequence_t::SEQUENCE_READY_HELP_MESSAGE));
    2366           1 :         ed::communicator::instance()->add_connection(messenger);
    2367           1 :         messenger_timer::pointer_t timer(std::make_shared<messenger_timer>(messenger));
    2368           1 :         ed::communicator::instance()->add_connection(timer);
    2369           1 :         messenger->set_timer(timer);
    2370             : 
    2371           1 :         CATCH_REQUIRE(e->run());
    2372             : 
    2373             :         // if we exited because of our timer, then the test did not pass
    2374             :         //
    2375           1 :         CATCH_REQUIRE_FALSE(timer->timed_out_prima());
    2376             : 
    2377           1 :         CATCH_REQUIRE(s->get_exit_code() == 0);
    2378             : 
    2379             :         // we unset that variable, make sure that worked
    2380             :         //
    2381           3 :         SNAP_CATCH2_NAMESPACE::reporter::variable::pointer_t var(s->get_variable("got_register"));
    2382           1 :         CATCH_REQUIRE(var == nullptr);
    2383           1 :     }
    2384           9 :     CATCH_END_SECTION()
    2385             : 
    2386           9 :     CATCH_START_SECTION("verify last wait (disconnect -> HUP)")
    2387             :     {
    2388           1 :         SNAP_CATCH2_NAMESPACE::reporter::lexer::pointer_t l(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::lexer>("program_verify_last_wait.rprtr", g_program_last_wait));
    2389           1 :         SNAP_CATCH2_NAMESPACE::reporter::state::pointer_t s(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::state>());
    2390           1 :         SNAP_CATCH2_NAMESPACE::reporter::parser::pointer_t p(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::parser>(l, s));
    2391           1 :         p->parse_program();
    2392             : 
    2393           1 :         SNAP_CATCH2_NAMESPACE::reporter::executor::pointer_t e(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::executor>(s));
    2394           1 :         e->start();
    2395           1 :         addr::addr a;
    2396           1 :         sockaddr_in ip = {
    2397             :             .sin_family = AF_INET,
    2398           1 :             .sin_port = htons(20002),
    2399             :             .sin_addr = {
    2400           1 :                 .s_addr = htonl(0x7f000001),
    2401             :             },
    2402             :             .sin_zero = {},
    2403           1 :         };
    2404           1 :         a.set_ipv4(ip);
    2405           1 :         messenger_responder::pointer_t messenger(std::make_shared<messenger_responder>(
    2406             :                   a
    2407           1 :                 , ed::mode_t::MODE_PLAIN
    2408           2 :                 , messenger_responder::sequence_t::SEQUENCE_ONE_MESSAGE));
    2409           1 :         ed::communicator::instance()->add_connection(messenger);
    2410           1 :         messenger_timer::pointer_t timer(std::make_shared<messenger_timer>(messenger));
    2411           1 :         ed::communicator::instance()->add_connection(timer);
    2412           1 :         messenger->set_timer(timer);
    2413           1 :         e->set_thread_done_callback([messenger, timer]()
    2414             :             {
    2415           1 :                 ed::communicator::instance()->remove_connection(messenger);
    2416           1 :                 ed::communicator::instance()->remove_connection(timer);
    2417           1 :             });
    2418           1 :         CATCH_REQUIRE(e->run());
    2419           1 :         e->stop();
    2420             : 
    2421             :         // if we exited because of our timer, then the test did not pass
    2422             :         //
    2423           1 :         CATCH_REQUIRE_FALSE(timer->timed_out_prima());
    2424             : 
    2425           1 :         CATCH_REQUIRE(s->get_exit_code() == 0);
    2426           1 :     }
    2427           9 :     CATCH_END_SECTION()
    2428             : 
    2429           9 :     CATCH_START_SECTION("wait for timeout (to make sure we DO NOT receive extra messages)")
    2430             :     {
    2431           1 :         SNAP_CATCH2_NAMESPACE::reporter::lexer::pointer_t l(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::lexer>("program_wait_for_timeout.rprtr", g_program_wait_for_timeout));
    2432           1 :         SNAP_CATCH2_NAMESPACE::reporter::state::pointer_t s(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::state>());
    2433           1 :         SNAP_CATCH2_NAMESPACE::reporter::parser::pointer_t p(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::parser>(l, s));
    2434           1 :         p->parse_program();
    2435             : 
    2436           1 :         SNAP_CATCH2_NAMESPACE::reporter::executor::pointer_t e(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::executor>(s));
    2437           1 :         e->start();
    2438           1 :         addr::addr a;
    2439           1 :         sockaddr_in ip = {
    2440             :             .sin_family = AF_INET,
    2441           1 :             .sin_port = htons(20002),
    2442             :             .sin_addr = {
    2443           1 :                 .s_addr = htonl(0x7f000001),
    2444             :             },
    2445             :             .sin_zero = {},
    2446           1 :         };
    2447           1 :         a.set_ipv4(ip);
    2448           1 :         messenger_responder::pointer_t messenger(std::make_shared<messenger_responder>(
    2449             :                   a
    2450           1 :                 , ed::mode_t::MODE_PLAIN
    2451           2 :                 , messenger_responder::sequence_t::SEQUENCE_ONE_MESSAGE));
    2452           1 :         ed::communicator::instance()->add_connection(messenger);
    2453           1 :         messenger_timer::pointer_t timer(std::make_shared<messenger_timer>(messenger));
    2454           1 :         ed::communicator::instance()->add_connection(timer);
    2455           1 :         messenger->set_timer(timer);
    2456           1 :         e->set_thread_done_callback([messenger, timer]()
    2457             :             {
    2458           1 :                 ed::communicator::instance()->remove_connection(messenger);
    2459           1 :                 ed::communicator::instance()->remove_connection(timer);
    2460           1 :             });
    2461           1 :         CATCH_REQUIRE(e->run());
    2462           1 :         e->stop();
    2463             : 
    2464           1 :         CATCH_REQUIRE_FALSE(timer->timed_out_prima());
    2465           1 :         CATCH_REQUIRE(s->get_exit_code() == 0);
    2466           1 :     }
    2467           9 :     CATCH_END_SECTION()
    2468           9 : }
    2469             : 
    2470             : 
    2471           8 : CATCH_TEST_CASE("reporter_executor_variables", "[executor][reporter][variable]")
    2472             : {
    2473           8 :     CATCH_START_SECTION("undefined variable")
    2474             :     {
    2475           1 :         SNAP_CATCH2_NAMESPACE::reporter::lexer::pointer_t l(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::lexer>("program_undefined_variable.rprtr", g_program_undefined_variable));
    2476           1 :         SNAP_CATCH2_NAMESPACE::reporter::state::pointer_t s(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::state>());
    2477           1 :         SNAP_CATCH2_NAMESPACE::reporter::parser::pointer_t p(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::parser>(l, s));
    2478           1 :         p->parse_program();
    2479             : 
    2480           1 :         CATCH_REQUIRE(s->get_statement_size() == 5);
    2481             : 
    2482           1 :         SNAP_CATCH2_NAMESPACE::reporter::executor::pointer_t e(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::executor>(s));
    2483           1 :         e->start();
    2484           1 :         CATCH_REQUIRE(e->run());
    2485             : 
    2486           1 :         CATCH_REQUIRE(s->get_exit_code() == 0);
    2487           1 :     }
    2488           8 :     CATCH_END_SECTION()
    2489             : 
    2490           8 :     CATCH_START_SECTION("detect integer variable")
    2491             :     {
    2492           1 :         SNAP_CATCH2_NAMESPACE::reporter::lexer::pointer_t l(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::lexer>("program_integer_variable.rprtr", g_program_integer_variable));
    2493           1 :         SNAP_CATCH2_NAMESPACE::reporter::state::pointer_t s(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::state>());
    2494           1 :         SNAP_CATCH2_NAMESPACE::reporter::parser::pointer_t p(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::parser>(l, s));
    2495           1 :         p->parse_program();
    2496             : 
    2497           1 :         CATCH_REQUIRE(s->get_statement_size() == 10);
    2498             : 
    2499           1 :         SNAP_CATCH2_NAMESPACE::reporter::executor::pointer_t e(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::executor>(s));
    2500           1 :         e->start();
    2501           1 :         CATCH_REQUIRE(e->run());
    2502             : 
    2503           1 :         CATCH_REQUIRE(s->get_exit_code() == 0);
    2504           1 :     }
    2505           8 :     CATCH_END_SECTION()
    2506             : 
    2507           8 :     CATCH_START_SECTION("detect string variable")
    2508             :     {
    2509           1 :         SNAP_CATCH2_NAMESPACE::reporter::lexer::pointer_t l(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::lexer>("program_string_variable.rprtr", g_program_string_variable));
    2510           1 :         SNAP_CATCH2_NAMESPACE::reporter::state::pointer_t s(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::state>());
    2511           1 :         SNAP_CATCH2_NAMESPACE::reporter::parser::pointer_t p(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::parser>(l, s));
    2512           1 :         p->parse_program();
    2513             : 
    2514           1 :         CATCH_REQUIRE(s->get_statement_size() == 10);
    2515             : 
    2516           1 :         SNAP_CATCH2_NAMESPACE::reporter::executor::pointer_t e(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::executor>(s));
    2517           1 :         e->start();
    2518           1 :         CATCH_REQUIRE(e->run());
    2519             : 
    2520           1 :         CATCH_REQUIRE(s->get_exit_code() == 0);
    2521           1 :     }
    2522           8 :     CATCH_END_SECTION()
    2523             : 
    2524           8 :     CATCH_START_SECTION("if variable")
    2525             :     {
    2526           1 :         SNAP_CATCH2_NAMESPACE::reporter::lexer::pointer_t l(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::lexer>("program_if_variable.rprtr", g_program_if_variable));
    2527           1 :         SNAP_CATCH2_NAMESPACE::reporter::state::pointer_t s(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::state>());
    2528           1 :         SNAP_CATCH2_NAMESPACE::reporter::parser::pointer_t p(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::parser>(l, s));
    2529           1 :         p->parse_program();
    2530             : 
    2531           1 :         CATCH_REQUIRE(s->get_statement_size() == 104);
    2532             : 
    2533           1 :         SNAP_CATCH2_NAMESPACE::reporter::executor::pointer_t e(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::executor>(s));
    2534           1 :         e->start();
    2535           1 :         CATCH_REQUIRE(e->run());
    2536             : 
    2537           1 :         CATCH_REQUIRE(s->get_exit_code() == 0);
    2538           1 :     }
    2539           8 :     CATCH_END_SECTION()
    2540             : 
    2541           8 :     CATCH_START_SECTION("void variable cloning")
    2542             :     {
    2543             :         // Note: at the moment there is no call to the clone() function
    2544             :         //       inside the library, so make sure it works as expected
    2545             :         //       within the test
    2546             :         //
    2547           2 :         SNAP_CATCH2_NAMESPACE::reporter::variable::pointer_t var(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::variable_void>("void_var"));
    2548           1 :         CATCH_REQUIRE(var != nullptr);
    2549             : 
    2550           1 :         SNAP_CATCH2_NAMESPACE::reporter::variable_void::pointer_t v(std::dynamic_pointer_cast<SNAP_CATCH2_NAMESPACE::reporter::variable_void>(var));
    2551           1 :         CATCH_REQUIRE(v != nullptr);
    2552             : 
    2553           3 :         SNAP_CATCH2_NAMESPACE::reporter::variable::pointer_t clone(v->clone("clone"));
    2554           1 :         CATCH_REQUIRE(clone != nullptr);
    2555             : 
    2556           1 :         SNAP_CATCH2_NAMESPACE::reporter::variable_void::pointer_t c(std::dynamic_pointer_cast<SNAP_CATCH2_NAMESPACE::reporter::variable_void>(clone));
    2557           1 :         CATCH_REQUIRE(c != nullptr);
    2558             : 
    2559           3 :         SNAP_CATCH2_NAMESPACE::reporter::variable::pointer_t clone2(var->clone("clone2"));
    2560           1 :         CATCH_REQUIRE(clone2 != nullptr);
    2561             : 
    2562           1 :         SNAP_CATCH2_NAMESPACE::reporter::variable_void::pointer_t c2(std::dynamic_pointer_cast<SNAP_CATCH2_NAMESPACE::reporter::variable_void>(clone2));
    2563           1 :         CATCH_REQUIRE(c2 != nullptr);
    2564           1 :     }
    2565           8 :     CATCH_END_SECTION()
    2566             : 
    2567           8 :     CATCH_START_SECTION("list variable")
    2568             :     {
    2569             :         // Note: some of the list variable functions are not fully tested
    2570             :         //       from within the app. so test more here
    2571             :         //
    2572           2 :         SNAP_CATCH2_NAMESPACE::reporter::variable::pointer_t list(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::variable_list>("list_var"));
    2573           1 :         CATCH_REQUIRE(list != nullptr);
    2574             : 
    2575           1 :         SNAP_CATCH2_NAMESPACE::reporter::variable_list::pointer_t l(std::dynamic_pointer_cast<SNAP_CATCH2_NAMESPACE::reporter::variable_list>(list));
    2576           1 :         CATCH_REQUIRE(l != nullptr);
    2577             : 
    2578           1 :         CATCH_REQUIRE(l->get_item_size() == 0);
    2579             : 
    2580           2 :         SNAP_CATCH2_NAMESPACE::reporter::variable::pointer_t var1(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::variable_void>("void_var"));
    2581           1 :         CATCH_REQUIRE(var1 != nullptr);
    2582           1 :         l->add_item(var1);
    2583           1 :         CATCH_REQUIRE(l->get_item(0) == var1);
    2584           1 :         CATCH_REQUIRE(l->get_item(-1) == nullptr);
    2585           1 :         CATCH_REQUIRE(l->get_item(1) == nullptr);
    2586             : 
    2587           2 :         SNAP_CATCH2_NAMESPACE::reporter::variable::pointer_t var2(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::variable_integer>("integer_var"));
    2588           1 :         CATCH_REQUIRE(var2 != nullptr);
    2589           1 :         l->add_item(var2);
    2590           1 :         CATCH_REQUIRE(l->get_item(0) == var2);      // this is a map so the order is sorted by variable name
    2591           1 :         CATCH_REQUIRE(l->get_item(-1) == nullptr);
    2592           1 :         CATCH_REQUIRE(l->get_item(1) == var1);
    2593           1 :         CATCH_REQUIRE(l->get_item(2) == nullptr);
    2594           1 :         CATCH_REQUIRE(l->get_item("void_var") == var1);
    2595           1 :         CATCH_REQUIRE(l->get_item("integer_var") == var2);
    2596           1 :         CATCH_REQUIRE(l->get_item("undefined_var") == nullptr);
    2597             : 
    2598           3 :         CATCH_REQUIRE_THROWS_MATCHES(
    2599             :               l->add_item(var1)
    2600             :             , std::runtime_error
    2601             :             , Catch::Matchers::ExceptionMessage("variable_list::add_item() trying to re-add item named \"void_var\"."));
    2602             : 
    2603           3 :         CATCH_REQUIRE_THROWS_MATCHES(
    2604             :               l->add_item(var2)
    2605             :             , std::runtime_error
    2606             :             , Catch::Matchers::ExceptionMessage("variable_list::add_item() trying to re-add item named \"integer_var\"."));
    2607             : 
    2608           3 :         SNAP_CATCH2_NAMESPACE::reporter::variable::pointer_t clone(list->clone("clone"));
    2609           1 :         CATCH_REQUIRE(clone != nullptr);
    2610           1 :         SNAP_CATCH2_NAMESPACE::reporter::variable_list::pointer_t l2(std::dynamic_pointer_cast<SNAP_CATCH2_NAMESPACE::reporter::variable_list>(clone));
    2611           1 :         CATCH_REQUIRE(l2 != nullptr);
    2612             : 
    2613           1 :         CATCH_REQUIRE(l2->get_item(-1) == nullptr);
    2614           1 :         CATCH_REQUIRE(l2->get_item(2) == nullptr);
    2615             : 
    2616             :         // the items are also cloned so we can quickly test that they are not
    2617             :         // equal and then we can verify the type or the name
    2618             :         //
    2619           1 :         CATCH_REQUIRE(l2->get_item(0) != var1);
    2620           1 :         CATCH_REQUIRE(l2->get_item(1) != var1);
    2621           1 :         CATCH_REQUIRE(l2->get_item(0) != var2);
    2622           1 :         CATCH_REQUIRE(l2->get_item(1) != var2);
    2623             : 
    2624           1 :         CATCH_REQUIRE(l2->get_item(0)->get_type() == "integer");
    2625           1 :         CATCH_REQUIRE(l2->get_item(1)->get_type() == "void");
    2626             : 
    2627             :         // make sure original is still valid
    2628             :         //
    2629           1 :         CATCH_REQUIRE(l->get_item(0) == var2);
    2630           1 :         CATCH_REQUIRE(l->get_item(-1) == nullptr);
    2631           1 :         CATCH_REQUIRE(l->get_item(1) == var1);
    2632           1 :         CATCH_REQUIRE(l->get_item(2) == nullptr);
    2633           1 :     }
    2634           8 :     CATCH_END_SECTION()
    2635             : 
    2636           8 :     CATCH_START_SECTION("primary variable references")
    2637             :     {
    2638           1 :         SNAP_CATCH2_NAMESPACE::reporter::lexer::pointer_t l(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::lexer>("primary_variable_references.rprtr", g_program_primary_variable_references));
    2639           1 :         SNAP_CATCH2_NAMESPACE::reporter::state::pointer_t s(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::state>());
    2640           1 :         SNAP_CATCH2_NAMESPACE::reporter::parser::pointer_t p(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::parser>(l, s));
    2641           1 :         p->parse_program();
    2642             : 
    2643           1 :         CATCH_REQUIRE(s->get_statement_size() == 14);
    2644             : 
    2645           3 :         SNAP_CATCH2_NAMESPACE::reporter::variable::pointer_t var(s->get_variable("my_string_var"));
    2646           1 :         CATCH_REQUIRE(var == nullptr);
    2647           1 :         var = s->get_variable("longer_string_var");
    2648           1 :         CATCH_REQUIRE(var == nullptr);
    2649           1 :         var = s->get_variable("my_integer_var");
    2650           1 :         CATCH_REQUIRE(var == nullptr);
    2651           1 :         var = s->get_variable("longer_integer_var");
    2652           1 :         CATCH_REQUIRE(var == nullptr);
    2653           1 :         var = s->get_variable("my_floating_point_var");
    2654           1 :         CATCH_REQUIRE(var == nullptr);
    2655           1 :         var = s->get_variable("longer_floating_point_var");
    2656           1 :         CATCH_REQUIRE(var == nullptr);
    2657           1 :         var = s->get_variable("my_identifier_var");
    2658           1 :         CATCH_REQUIRE(var == nullptr);
    2659           1 :         var = s->get_variable("longer_identifier_var");
    2660           1 :         CATCH_REQUIRE(var == nullptr);
    2661           1 :         var = s->get_variable("my_regex_var");
    2662           1 :         CATCH_REQUIRE(var == nullptr);
    2663           1 :         var = s->get_variable("longer_regex_var");
    2664           1 :         CATCH_REQUIRE(var == nullptr);
    2665           1 :         var = s->get_variable("my_address_var");
    2666           1 :         CATCH_REQUIRE(var == nullptr);
    2667           1 :         var = s->get_variable("longer_address_var");
    2668           1 :         CATCH_REQUIRE(var == nullptr);
    2669           1 :         var = s->get_variable("my_timestamp_var");
    2670           1 :         CATCH_REQUIRE(var == nullptr);
    2671           1 :         var = s->get_variable("longer_timestamp_var");
    2672           1 :         CATCH_REQUIRE(var == nullptr);
    2673             : 
    2674           1 :         SNAP_CATCH2_NAMESPACE::reporter::executor::pointer_t e(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::executor>(s));
    2675           1 :         e->start();
    2676           1 :         CATCH_REQUIRE(e->run());
    2677             : 
    2678           1 :         var = s->get_variable("my_string_var");
    2679           1 :         CATCH_REQUIRE(var != nullptr);
    2680           1 :         SNAP_CATCH2_NAMESPACE::reporter::variable_string::pointer_t vs(std::dynamic_pointer_cast<SNAP_CATCH2_NAMESPACE::reporter::variable_string>(var));
    2681           1 :         CATCH_REQUIRE(vs != nullptr);
    2682           1 :         CATCH_REQUIRE(vs->get_type() == "string");
    2683           1 :         CATCH_REQUIRE(vs->get_string() == "foo");
    2684             : 
    2685           1 :         var = s->get_variable("longer_string_var");
    2686           1 :         CATCH_REQUIRE(var != nullptr);
    2687           1 :         vs = std::dynamic_pointer_cast<SNAP_CATCH2_NAMESPACE::reporter::variable_string>(var);
    2688           1 :         CATCH_REQUIRE(vs != nullptr);
    2689           1 :         CATCH_REQUIRE(vs->get_type() == "string");
    2690           1 :         CATCH_REQUIRE(vs->get_string() == "foo");
    2691             : 
    2692           1 :         var = s->get_variable("my_integer_var");
    2693           1 :         CATCH_REQUIRE(var != nullptr);
    2694           1 :         SNAP_CATCH2_NAMESPACE::reporter::variable_integer::pointer_t vi(std::dynamic_pointer_cast<SNAP_CATCH2_NAMESPACE::reporter::variable_integer>(var));
    2695           1 :         CATCH_REQUIRE(vi != nullptr);
    2696           1 :         CATCH_REQUIRE(vi->get_type() == "integer");
    2697           1 :         CATCH_REQUIRE(vi->get_integer() == 41);
    2698             : 
    2699           1 :         var = s->get_variable("longer_integer_var");
    2700           1 :         CATCH_REQUIRE(var != nullptr);
    2701           1 :         vi = std::dynamic_pointer_cast<SNAP_CATCH2_NAMESPACE::reporter::variable_integer>(var);
    2702           1 :         CATCH_REQUIRE(vi != nullptr);
    2703           1 :         CATCH_REQUIRE(vi->get_type() == "integer");
    2704           1 :         CATCH_REQUIRE(vi->get_integer() == 41);
    2705             : 
    2706           1 :         var = s->get_variable("my_floating_point_var");
    2707           1 :         CATCH_REQUIRE(var != nullptr);
    2708           1 :         SNAP_CATCH2_NAMESPACE::reporter::variable_floating_point::pointer_t vf(std::dynamic_pointer_cast<SNAP_CATCH2_NAMESPACE::reporter::variable_floating_point>(var));
    2709           1 :         CATCH_REQUIRE(vf != nullptr);
    2710           1 :         CATCH_REQUIRE(vf->get_type() == "floating_point");
    2711           1 :         CATCH_REQUIRE(vf->get_floating_point() == 303.601);
    2712             : 
    2713           1 :         var = s->get_variable("longer_floating_point_var");
    2714           1 :         CATCH_REQUIRE(var != nullptr);
    2715           1 :         vf = std::dynamic_pointer_cast<SNAP_CATCH2_NAMESPACE::reporter::variable_floating_point>(var);
    2716           1 :         CATCH_REQUIRE(vf != nullptr);
    2717           1 :         CATCH_REQUIRE(vf->get_type() == "floating_point");
    2718           1 :         CATCH_REQUIRE(vf->get_floating_point() == 303.601);
    2719             : 
    2720           1 :         var = s->get_variable("my_identifier_var");
    2721           1 :         CATCH_REQUIRE(var != nullptr);
    2722           1 :         vs = std::dynamic_pointer_cast<SNAP_CATCH2_NAMESPACE::reporter::variable_string>(var);
    2723           1 :         CATCH_REQUIRE(vs != nullptr);
    2724           1 :         CATCH_REQUIRE(vs->get_type() == "identifier");
    2725           1 :         CATCH_REQUIRE(vs->get_string() == "bar");
    2726             : 
    2727           1 :         var = s->get_variable("longer_identifier_var");
    2728           1 :         CATCH_REQUIRE(var != nullptr);
    2729           1 :         vs = std::dynamic_pointer_cast<SNAP_CATCH2_NAMESPACE::reporter::variable_string>(var);
    2730           1 :         CATCH_REQUIRE(vs != nullptr);
    2731           1 :         CATCH_REQUIRE(vs->get_type() == "identifier");
    2732           1 :         CATCH_REQUIRE(vs->get_string() == "bar");
    2733             : 
    2734           1 :         var = s->get_variable("my_regex_var");
    2735           1 :         CATCH_REQUIRE(var != nullptr);
    2736           1 :         SNAP_CATCH2_NAMESPACE::reporter::variable_regex::pointer_t vre(std::dynamic_pointer_cast<SNAP_CATCH2_NAMESPACE::reporter::variable_regex>(var));
    2737           1 :         CATCH_REQUIRE(vre != nullptr);
    2738           1 :         CATCH_REQUIRE(vre->get_type() == "regex");
    2739           1 :         CATCH_REQUIRE(vre->get_regex() == "^[regex]$");
    2740             : 
    2741           1 :         var = s->get_variable("longer_regex_var");
    2742           1 :         CATCH_REQUIRE(var != nullptr);
    2743           1 :         vre = std::dynamic_pointer_cast<SNAP_CATCH2_NAMESPACE::reporter::variable_regex>(var);
    2744           1 :         CATCH_REQUIRE(vre != nullptr);
    2745           1 :         CATCH_REQUIRE(vre->get_type() == "regex");
    2746           1 :         CATCH_REQUIRE(vre->get_regex() == "^[regex]$");
    2747             : 
    2748           1 :         addr::addr a;
    2749           1 :         sockaddr_in ip = {
    2750             :             .sin_family = AF_INET,
    2751           1 :             .sin_port = htons(89),
    2752             :             .sin_addr = {
    2753           1 :                 .s_addr = htonl(0x0A0C0E10),
    2754             :             },
    2755             :             .sin_zero = {},
    2756           1 :         };
    2757           1 :         a.set_ipv4(ip);
    2758             : 
    2759           1 :         var = s->get_variable("my_address_var");
    2760           1 :         CATCH_REQUIRE(var != nullptr);
    2761           1 :         SNAP_CATCH2_NAMESPACE::reporter::variable_address::pointer_t va(std::dynamic_pointer_cast<SNAP_CATCH2_NAMESPACE::reporter::variable_address>(var));
    2762           1 :         CATCH_REQUIRE(va != nullptr);
    2763           1 :         CATCH_REQUIRE(va->get_type() == "address");
    2764           1 :         CATCH_REQUIRE(va->get_address() == a);
    2765             : 
    2766           1 :         var = s->get_variable("longer_address_var");
    2767           1 :         CATCH_REQUIRE(var != nullptr);
    2768           1 :         va = std::dynamic_pointer_cast<SNAP_CATCH2_NAMESPACE::reporter::variable_address>(var);
    2769           1 :         CATCH_REQUIRE(va != nullptr);
    2770           1 :         CATCH_REQUIRE(va->get_type() == "address");
    2771           1 :         CATCH_REQUIRE(va->get_address() == a);
    2772             : 
    2773           1 :         snapdev::timespec_ex const expected_timestamp{ 1714241733, 419438123 };
    2774             : 
    2775           1 :         var = s->get_variable("my_timestamp_var");
    2776           1 :         CATCH_REQUIRE(var != nullptr);
    2777           1 :         SNAP_CATCH2_NAMESPACE::reporter::variable_timestamp::pointer_t vts(std::dynamic_pointer_cast<SNAP_CATCH2_NAMESPACE::reporter::variable_timestamp>(var));
    2778           1 :         CATCH_REQUIRE(vts != nullptr);
    2779           1 :         CATCH_REQUIRE(vts->get_type() == "timestamp");
    2780           1 :         CATCH_REQUIRE(vts->get_timestamp() == expected_timestamp);
    2781             : 
    2782           1 :         var = s->get_variable("longer_timestamp_var");
    2783           1 :         CATCH_REQUIRE(var != nullptr);
    2784           1 :         vts = std::dynamic_pointer_cast<SNAP_CATCH2_NAMESPACE::reporter::variable_timestamp>(var);
    2785           1 :         CATCH_REQUIRE(vts != nullptr);
    2786           1 :         CATCH_REQUIRE(vts->get_type() == "timestamp");
    2787           1 :         CATCH_REQUIRE(vts->get_timestamp() == expected_timestamp);
    2788             : 
    2789           1 :         CATCH_REQUIRE(s->get_exit_code() == -1);
    2790           1 :     }
    2791           8 :     CATCH_END_SECTION()
    2792             : 
    2793           8 :     CATCH_START_SECTION("primary variable reference with wrong name")
    2794             :     {
    2795           1 :         SNAP_CATCH2_NAMESPACE::reporter::lexer::pointer_t l(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::lexer>("primary_variable_reference.rprtr", g_program_wrong_primary_variable_reference));
    2796           1 :         SNAP_CATCH2_NAMESPACE::reporter::state::pointer_t s(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::state>());
    2797           1 :         SNAP_CATCH2_NAMESPACE::reporter::parser::pointer_t p(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::parser>(l, s));
    2798           1 :         p->parse_program();
    2799             : 
    2800           1 :         CATCH_REQUIRE(s->get_statement_size() == 2);
    2801             : 
    2802           3 :         SNAP_CATCH2_NAMESPACE::reporter::variable::pointer_t var(s->get_variable("my_var"));
    2803           1 :         CATCH_REQUIRE(var == nullptr);
    2804           1 :         var = s->get_variable("longer_var");
    2805           1 :         CATCH_REQUIRE(var == nullptr);
    2806             : 
    2807           1 :         SNAP_CATCH2_NAMESPACE::reporter::executor::pointer_t e(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::executor>(s));
    2808           1 :         e->start();
    2809           1 :         CATCH_REQUIRE(e->run());
    2810             : 
    2811           1 :         var = s->get_variable("my_var");
    2812           1 :         CATCH_REQUIRE(var != nullptr);
    2813           1 :         SNAP_CATCH2_NAMESPACE::reporter::variable_string::pointer_t v(std::dynamic_pointer_cast<SNAP_CATCH2_NAMESPACE::reporter::variable_string>(var));
    2814           1 :         CATCH_REQUIRE(v != nullptr);
    2815           1 :         CATCH_REQUIRE(v->get_string() == "foo");
    2816             : 
    2817           1 :         var = s->get_variable("longer_var");
    2818           1 :         CATCH_REQUIRE(var != nullptr);
    2819           1 :         v = std::dynamic_pointer_cast<SNAP_CATCH2_NAMESPACE::reporter::variable_string>(var);
    2820           1 :         CATCH_REQUIRE(v != nullptr);
    2821           1 :         CATCH_REQUIRE(v->get_string() == ""); // wrong name so we get an empty string
    2822             : 
    2823           1 :         CATCH_REQUIRE(s->get_exit_code() == -1);
    2824           1 :     }
    2825           8 :     CATCH_END_SECTION()
    2826           8 : }
    2827             : 
    2828             : 
    2829          28 : CATCH_TEST_CASE("reporter_executor_error", "[executor][reporter][error]")
    2830             : {
    2831          28 :     CATCH_START_SECTION("if() before any condition")
    2832             :     {
    2833           1 :         SNAP_CATCH2_NAMESPACE::reporter::lexer::pointer_t l(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::lexer>("if_too_soon.rprtr.rprtr", g_program_no_condition));
    2834           1 :         SNAP_CATCH2_NAMESPACE::reporter::state::pointer_t s(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::state>());
    2835           1 :         SNAP_CATCH2_NAMESPACE::reporter::parser::pointer_t p(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::parser>(l, s));
    2836           1 :         p->parse_program();
    2837             : 
    2838           1 :         CATCH_REQUIRE(s->get_statement_size() == 2);
    2839             : 
    2840           1 :         SNAP_CATCH2_NAMESPACE::reporter::executor::pointer_t e(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::executor>(s));
    2841           1 :         CATCH_REQUIRE_THROWS_MATCHES(
    2842             :               e->start()
    2843             :             , std::runtime_error
    2844             :             , Catch::Matchers::ExceptionMessage(
    2845             :                       "trying to use a 'compare' result when none are currently defined."));
    2846             : 
    2847           1 :         CATCH_REQUIRE_THROWS_MATCHES(
    2848             :               s->set_compare(SNAP_CATCH2_NAMESPACE::reporter::compare_t::COMPARE_UNDEFINED)
    2849             :             , std::runtime_error
    2850             :             , Catch::Matchers::ExceptionMessage(
    2851             :                       "'compare' cannot be set to \"undefined\"."));
    2852           1 :     }
    2853          28 :     CATCH_END_SECTION()
    2854             : 
    2855          28 :     CATCH_START_SECTION("exit() + error message")
    2856             :     {
    2857           1 :         SNAP_CATCH2_NAMESPACE::reporter::lexer::pointer_t l(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::lexer>("exit_error_message.rprtr.rprtr", g_program_error_message));
    2858           1 :         SNAP_CATCH2_NAMESPACE::reporter::state::pointer_t s(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::state>());
    2859           1 :         SNAP_CATCH2_NAMESPACE::reporter::parser::pointer_t p(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::parser>(l, s));
    2860           1 :         p->parse_program();
    2861             : 
    2862           1 :         CATCH_REQUIRE(s->get_statement_size() == 1);
    2863             : 
    2864           1 :         SNAP_CATCH2_NAMESPACE::reporter::executor::pointer_t e(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::executor>(s));
    2865           1 :         e->start();
    2866             : 
    2867           1 :         CATCH_REQUIRE(s->get_exit_code() == 1);
    2868           1 :     }
    2869          28 :     CATCH_END_SECTION()
    2870             : 
    2871          28 :     CATCH_START_SECTION("listen() + listen()")
    2872             :     {
    2873           1 :         SNAP_CATCH2_NAMESPACE::reporter::lexer::pointer_t l(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::lexer>("two_listen.rprtr.rprtr", g_program_two_listen));
    2874           1 :         SNAP_CATCH2_NAMESPACE::reporter::state::pointer_t s(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::state>());
    2875           1 :         SNAP_CATCH2_NAMESPACE::reporter::parser::pointer_t p(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::parser>(l, s));
    2876           1 :         p->parse_program();
    2877             : 
    2878           1 :         CATCH_REQUIRE(s->get_statement_size() == 2);
    2879             : 
    2880           1 :         SNAP_CATCH2_NAMESPACE::reporter::executor::pointer_t e(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::executor>(s));
    2881           1 :         CATCH_REQUIRE_THROWS_MATCHES(
    2882             :               e->start()
    2883             :             , std::runtime_error
    2884             :             , Catch::Matchers::ExceptionMessage(
    2885             :                       "the listen() instruction cannot be reused without an intermediate disconnect() instruction."));
    2886           1 :     }
    2887          28 :     CATCH_END_SECTION()
    2888             : 
    2889          28 :     CATCH_START_SECTION("label(name: ...) does not accept integers")
    2890             :     {
    2891           1 :         SNAP_CATCH2_NAMESPACE::reporter::lexer::pointer_t l(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::lexer>("label_bad_type.rprtr.rprtr", g_program_label_bad_type));
    2892           1 :         SNAP_CATCH2_NAMESPACE::reporter::state::pointer_t s(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::state>());
    2893           1 :         SNAP_CATCH2_NAMESPACE::reporter::parser::pointer_t p(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::parser>(l, s));
    2894             : 
    2895             :         // label is a special case which we test in the state.cpp way before
    2896             :         // we reach the executor... (so this is not really an executor test)
    2897             :         //
    2898           1 :         CATCH_REQUIRE_THROWS_MATCHES(
    2899             :               p->parse_program()
    2900             :             , std::runtime_error
    2901             :             , Catch::Matchers::ExceptionMessage(
    2902             :                       "the value of the \"name\" parameter of the \"label\" statement must be an identifier."));
    2903           1 :     }
    2904          28 :     CATCH_END_SECTION()
    2905             : 
    2906          28 :     CATCH_START_SECTION("exit(error_message: ...) does not accept floating points")
    2907             :     {
    2908           1 :         SNAP_CATCH2_NAMESPACE::reporter::lexer::pointer_t l(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::lexer>("exit_bad_type.rprtr", g_program_exit_bad_type));
    2909           1 :         SNAP_CATCH2_NAMESPACE::reporter::state::pointer_t s(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::state>());
    2910           1 :         SNAP_CATCH2_NAMESPACE::reporter::parser::pointer_t p(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::parser>(l, s));
    2911           1 :         p->parse_program();
    2912             : 
    2913           1 :         CATCH_REQUIRE(s->get_statement_size() == 1);
    2914             : 
    2915           1 :         SNAP_CATCH2_NAMESPACE::reporter::executor::pointer_t e(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::executor>(s));
    2916           1 :         CATCH_REQUIRE_THROWS_MATCHES(
    2917             :               e->start()
    2918             :             , std::runtime_error
    2919             :             , Catch::Matchers::ExceptionMessage(
    2920             :                       "parameter type mismatch for error_message, expected \"string\", got \"floating_point\" instead."));
    2921           1 :     }
    2922          28 :     CATCH_END_SECTION()
    2923             : 
    2924          28 :     CATCH_START_SECTION("verify starting the thread twice")
    2925             :     {
    2926           1 :         SNAP_CATCH2_NAMESPACE::reporter::lexer::pointer_t l(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::lexer>("program_start_thread_twice.rprtr", g_program_start_thread_twice));
    2927           1 :         SNAP_CATCH2_NAMESPACE::reporter::state::pointer_t s(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::state>());
    2928           1 :         SNAP_CATCH2_NAMESPACE::reporter::parser::pointer_t p(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::parser>(l, s));
    2929           1 :         p->parse_program();
    2930             : 
    2931           1 :         CATCH_REQUIRE(s->get_statement_size() == 4);
    2932             : 
    2933             :         // before we run the script, there are no such variables
    2934             :         //
    2935           3 :         SNAP_CATCH2_NAMESPACE::reporter::variable::pointer_t var(s->get_variable("test"));
    2936           1 :         CATCH_REQUIRE(var == nullptr);
    2937           1 :         var = s->get_variable("runner");
    2938           1 :         CATCH_REQUIRE(var == nullptr);
    2939             : 
    2940           1 :         SNAP_CATCH2_NAMESPACE::reporter::executor::pointer_t e(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::executor>(s));
    2941           1 :         e->start();
    2942           1 :         CATCH_REQUIRE(e->run());
    2943           1 :         CATCH_REQUIRE_THROWS_MATCHES(
    2944             :               e->stop()
    2945             :             , std::runtime_error
    2946             :             , Catch::Matchers::ExceptionMessage(
    2947             :                       "run() instruction found when already running in the background."));
    2948             : 
    2949           1 :         var = s->get_variable("test");
    2950           1 :         CATCH_REQUIRE(var != nullptr);
    2951           1 :         CATCH_REQUIRE(var->get_name() == "test");
    2952           1 :         CATCH_REQUIRE(var->get_type() == "integer");
    2953           1 :         CATCH_REQUIRE(std::static_pointer_cast<SNAP_CATCH2_NAMESPACE::reporter::variable_integer>(var)->get_integer() == 33);
    2954             : 
    2955           1 :         var = s->get_variable("runner");
    2956           1 :         CATCH_REQUIRE(var != nullptr);
    2957           1 :         CATCH_REQUIRE(var->get_name() == "runner");
    2958           1 :         CATCH_REQUIRE(var->get_type() == "floating_point");
    2959           1 :         CATCH_REQUIRE(std::static_pointer_cast<SNAP_CATCH2_NAMESPACE::reporter::variable_floating_point>(var)->get_floating_point() == 6.07);
    2960           1 :     }
    2961          28 :     CATCH_END_SECTION()
    2962             : 
    2963          28 :     CATCH_START_SECTION("<type> + <type> that are not valid")
    2964             :     {
    2965             :         struct bad_additions_t
    2966             :         {
    2967             :             char const *    f_code = nullptr;
    2968             :             SNAP_CATCH2_NAMESPACE::reporter::token_t  f_left_hand_side = SNAP_CATCH2_NAMESPACE::reporter::token_t::TOKEN_ERROR;
    2969             :             SNAP_CATCH2_NAMESPACE::reporter::token_t  f_right_hand_side = SNAP_CATCH2_NAMESPACE::reporter::token_t::TOKEN_ERROR;
    2970             :         };
    2971           1 :         constexpr bad_additions_t const bad_additions[] =
    2972             :         {
    2973             :             {
    2974             :                 g_program_unsupported_addition_address_address,
    2975             :                 SNAP_CATCH2_NAMESPACE::reporter::token_t::TOKEN_ADDRESS,
    2976             :                 SNAP_CATCH2_NAMESPACE::reporter::token_t::TOKEN_ADDRESS,
    2977             :             },
    2978             :             {
    2979             :                 g_program_unsupported_addition_address_string,
    2980             :                 SNAP_CATCH2_NAMESPACE::reporter::token_t::TOKEN_ADDRESS,
    2981             :                 SNAP_CATCH2_NAMESPACE::reporter::token_t::TOKEN_SINGLE_STRING,
    2982             :             },
    2983             :             {
    2984             :                 g_program_unsupported_addition_string_address,
    2985             :                 SNAP_CATCH2_NAMESPACE::reporter::token_t::TOKEN_SINGLE_STRING,
    2986             :                 SNAP_CATCH2_NAMESPACE::reporter::token_t::TOKEN_ADDRESS,
    2987             :             },
    2988             :             {
    2989             :                 g_program_unsupported_addition_address_identifier,
    2990             :                 SNAP_CATCH2_NAMESPACE::reporter::token_t::TOKEN_ADDRESS,
    2991             :                 SNAP_CATCH2_NAMESPACE::reporter::token_t::TOKEN_IDENTIFIER,
    2992             :             },
    2993             :             {
    2994             :                 g_program_unsupported_addition_identifier_address,
    2995             :                 SNAP_CATCH2_NAMESPACE::reporter::token_t::TOKEN_IDENTIFIER,
    2996             :                 SNAP_CATCH2_NAMESPACE::reporter::token_t::TOKEN_ADDRESS,
    2997             :             },
    2998             :             {
    2999             :                 g_program_unsupported_addition_identifier_string,
    3000             :                 SNAP_CATCH2_NAMESPACE::reporter::token_t::TOKEN_IDENTIFIER,
    3001             :                 SNAP_CATCH2_NAMESPACE::reporter::token_t::TOKEN_SINGLE_STRING,
    3002             :             },
    3003             :             {
    3004             :                 g_program_unsupported_addition_string_identifier,
    3005             :                 SNAP_CATCH2_NAMESPACE::reporter::token_t::TOKEN_SINGLE_STRING,
    3006             :                 SNAP_CATCH2_NAMESPACE::reporter::token_t::TOKEN_IDENTIFIER,
    3007             :             },
    3008             :         };
    3009             : 
    3010           8 :         for(auto const & ba : bad_additions)
    3011             :         {
    3012           7 :             SNAP_CATCH2_NAMESPACE::reporter::lexer::pointer_t l(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::lexer>("invalid_additions.rprtr", ba.f_code));
    3013           7 :             SNAP_CATCH2_NAMESPACE::reporter::state::pointer_t s(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::state>());
    3014           7 :             SNAP_CATCH2_NAMESPACE::reporter::parser::pointer_t p(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::parser>(l, s));
    3015           7 :             p->parse_program();
    3016             : 
    3017           7 :             CATCH_REQUIRE(s->get_statement_size() == 1);
    3018             : 
    3019           7 :             SNAP_CATCH2_NAMESPACE::reporter::executor::pointer_t e(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::executor>(s));
    3020           7 :             CATCH_REQUIRE_THROWS_MATCHES(
    3021             :                   e->start()
    3022             :                 , std::runtime_error
    3023             :                 , Catch::Matchers::ExceptionMessage(
    3024             :                           "unsupported addition (token types: "
    3025             :                         + std::to_string(static_cast<int>(ba.f_left_hand_side))
    3026             :                         + " + "
    3027             :                         + std::to_string(static_cast<int>(ba.f_right_hand_side))
    3028             :                         + ")."));
    3029           7 :         }
    3030             :     }
    3031          28 :     CATCH_END_SECTION()
    3032             : 
    3033          28 :     CATCH_START_SECTION("<type> - <type> that are not valid")
    3034             :     {
    3035           1 :         constexpr char const * const bad_subtractions[] =
    3036             :         {
    3037             :             g_program_unsupported_subtraction_address_string,
    3038             :             g_program_unsupported_subtraction_string_address,
    3039             :             g_program_unsupported_subtraction_address_identifier,
    3040             :             g_program_unsupported_subtraction_identifier_address,
    3041             :             g_program_unsupported_subtraction_identifier_string,
    3042             :             g_program_unsupported_subtraction_string_identifier,
    3043             :         };
    3044             : 
    3045           7 :         for(auto const & program : bad_subtractions)
    3046             :         {
    3047             : //std::cerr << "testing [" << program << "]\n";
    3048           6 :             SNAP_CATCH2_NAMESPACE::reporter::lexer::pointer_t l(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::lexer>("invalid_subtractions.rprtr", program));
    3049           6 :             SNAP_CATCH2_NAMESPACE::reporter::state::pointer_t s(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::state>());
    3050           6 :             SNAP_CATCH2_NAMESPACE::reporter::parser::pointer_t p(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::parser>(l, s));
    3051           6 :             p->parse_program();
    3052             : 
    3053           6 :             CATCH_REQUIRE(s->get_statement_size() == 1);
    3054             : 
    3055           6 :             SNAP_CATCH2_NAMESPACE::reporter::executor::pointer_t e(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::executor>(s));
    3056           6 :             CATCH_REQUIRE_THROWS_MATCHES(
    3057             :                   e->start()
    3058             :                 , std::runtime_error
    3059             :                 , Catch::Matchers::ExceptionMessage(
    3060             :                           "unsupported subtraction."));
    3061           6 :         }
    3062             :     }
    3063          28 :     CATCH_END_SECTION()
    3064             : 
    3065          28 :     CATCH_START_SECTION("<type> * <type> that are not valid")
    3066             :     {
    3067           1 :         constexpr char const * const bad_multiplications[] =
    3068             :         {
    3069             :             g_program_unsupported_multiplication_address_address,
    3070             :             g_program_unsupported_multiplication_address_string,
    3071             :             g_program_unsupported_multiplication_string_address,
    3072             :             g_program_unsupported_multiplication_address_identifier,
    3073             :             g_program_unsupported_multiplication_identifier_address,
    3074             :             g_program_unsupported_multiplication_identifier_string,
    3075             :             g_program_unsupported_multiplication_string_identifier,
    3076             :             g_program_unsupported_multiplication_string_string,
    3077             :             g_program_unsupported_multiplication_identifier_identifier,
    3078             :         };
    3079             : 
    3080          10 :         for(auto const & program : bad_multiplications)
    3081             :         {
    3082             : //std::cerr << "testing [" << program << "]\n";
    3083           9 :             SNAP_CATCH2_NAMESPACE::reporter::lexer::pointer_t l(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::lexer>("invalid_multiplications.rprtr", program));
    3084           9 :             SNAP_CATCH2_NAMESPACE::reporter::state::pointer_t s(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::state>());
    3085           9 :             SNAP_CATCH2_NAMESPACE::reporter::parser::pointer_t p(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::parser>(l, s));
    3086           9 :             p->parse_program();
    3087             : 
    3088           9 :             CATCH_REQUIRE(s->get_statement_size() == 1);
    3089             : 
    3090           9 :             SNAP_CATCH2_NAMESPACE::reporter::executor::pointer_t e(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::executor>(s));
    3091           9 :             CATCH_REQUIRE_THROWS_MATCHES(
    3092             :                   e->start()
    3093             :                 , std::runtime_error
    3094             :                 , Catch::Matchers::ExceptionMessage(
    3095             :                           "unsupported multiplication."));
    3096           9 :         }
    3097             :     }
    3098          28 :     CATCH_END_SECTION()
    3099             : 
    3100          28 :     CATCH_START_SECTION("<type> / <type> that are not valid")
    3101             :     {
    3102           1 :         constexpr char const * const bad_divisions[] =
    3103             :         {
    3104             :             g_program_unsupported_division_address_address,
    3105             :             g_program_unsupported_division_address_string,
    3106             :             g_program_unsupported_division_string_address,
    3107             :             g_program_unsupported_division_address_identifier,
    3108             :             g_program_unsupported_division_identifier_address,
    3109             :             g_program_unsupported_division_identifier_string,
    3110             :             g_program_unsupported_division_string_identifier,
    3111             :             g_program_unsupported_division_string_string,
    3112             :             g_program_unsupported_division_identifier_identifier,
    3113             :         };
    3114             : 
    3115          10 :         for(auto const & program : bad_divisions)
    3116             :         {
    3117             : //std::cerr << "testing [" << program << "]\n";
    3118           9 :             SNAP_CATCH2_NAMESPACE::reporter::lexer::pointer_t l(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::lexer>("invalid_divisions.rprtr", program));
    3119           9 :             SNAP_CATCH2_NAMESPACE::reporter::state::pointer_t s(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::state>());
    3120           9 :             SNAP_CATCH2_NAMESPACE::reporter::parser::pointer_t p(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::parser>(l, s));
    3121           9 :             p->parse_program();
    3122             : 
    3123           9 :             CATCH_REQUIRE(s->get_statement_size() == 1);
    3124             : 
    3125           9 :             SNAP_CATCH2_NAMESPACE::reporter::executor::pointer_t e(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::executor>(s));
    3126           9 :             CATCH_REQUIRE_THROWS_MATCHES(
    3127             :                   e->start()
    3128             :                 , std::runtime_error
    3129             :                 , Catch::Matchers::ExceptionMessage(
    3130             :                           "unsupported division."));
    3131           9 :         }
    3132             :     }
    3133          28 :     CATCH_END_SECTION()
    3134             : 
    3135          28 :     CATCH_START_SECTION("<type> % <type> that are not valid")
    3136             :     {
    3137             :         struct bad_modulo_t
    3138             :         {
    3139             :             char const * const                          f_expr = nullptr;
    3140             :             SNAP_CATCH2_NAMESPACE::reporter::token_t    f_lhs_token = SNAP_CATCH2_NAMESPACE::reporter::token_t::TOKEN_ERROR;
    3141             :             SNAP_CATCH2_NAMESPACE::reporter::token_t    f_rhs_token = SNAP_CATCH2_NAMESPACE::reporter::token_t::TOKEN_ERROR;
    3142             :         };
    3143           1 :         constexpr bad_modulo_t const bad_modulos[] =
    3144             :         {
    3145             :             {
    3146             :                 g_program_unsupported_modulo_address_address,
    3147             :                 SNAP_CATCH2_NAMESPACE::reporter::token_t::TOKEN_ADDRESS,
    3148             :                 SNAP_CATCH2_NAMESPACE::reporter::token_t::TOKEN_ADDRESS,
    3149             :             },
    3150             :             {
    3151             :                 g_program_unsupported_modulo_address_string,
    3152             :                 SNAP_CATCH2_NAMESPACE::reporter::token_t::TOKEN_ADDRESS,
    3153             :                 SNAP_CATCH2_NAMESPACE::reporter::token_t::TOKEN_SINGLE_STRING,
    3154             :             },
    3155             :             {
    3156             :                 g_program_unsupported_modulo_string_address,
    3157             :                 SNAP_CATCH2_NAMESPACE::reporter::token_t::TOKEN_SINGLE_STRING,
    3158             :                 SNAP_CATCH2_NAMESPACE::reporter::token_t::TOKEN_ADDRESS,
    3159             :             },
    3160             :             {
    3161             :                 g_program_unsupported_modulo_address_identifier,
    3162             :                 SNAP_CATCH2_NAMESPACE::reporter::token_t::TOKEN_ADDRESS,
    3163             :                 SNAP_CATCH2_NAMESPACE::reporter::token_t::TOKEN_IDENTIFIER,
    3164             :             },
    3165             :             {
    3166             :                 g_program_unsupported_modulo_identifier_address,
    3167             :                 SNAP_CATCH2_NAMESPACE::reporter::token_t::TOKEN_IDENTIFIER,
    3168             :                 SNAP_CATCH2_NAMESPACE::reporter::token_t::TOKEN_ADDRESS,
    3169             :             },
    3170             :             {
    3171             :                 g_program_unsupported_modulo_identifier_string,
    3172             :                 SNAP_CATCH2_NAMESPACE::reporter::token_t::TOKEN_IDENTIFIER,
    3173             :                 SNAP_CATCH2_NAMESPACE::reporter::token_t::TOKEN_SINGLE_STRING, // the type of string was already converted by this time
    3174             :             },
    3175             :             {
    3176             :                 g_program_unsupported_modulo_string_identifier,
    3177             :                 SNAP_CATCH2_NAMESPACE::reporter::token_t::TOKEN_SINGLE_STRING,
    3178             :                 SNAP_CATCH2_NAMESPACE::reporter::token_t::TOKEN_IDENTIFIER,
    3179             :             },
    3180             :             {
    3181             :                 g_program_unsupported_modulo_string_string,
    3182             :                 SNAP_CATCH2_NAMESPACE::reporter::token_t::TOKEN_SINGLE_STRING,
    3183             :                 SNAP_CATCH2_NAMESPACE::reporter::token_t::TOKEN_SINGLE_STRING, // the type of string was already converted by this time
    3184             :             },
    3185             :             {
    3186             :                 g_program_unsupported_modulo_identifier_identifier,
    3187             :                 SNAP_CATCH2_NAMESPACE::reporter::token_t::TOKEN_IDENTIFIER,
    3188             :                 SNAP_CATCH2_NAMESPACE::reporter::token_t::TOKEN_IDENTIFIER,
    3189             :             },
    3190             :         };
    3191             : 
    3192          10 :         for(auto const & program : bad_modulos)
    3193             :         {
    3194             : //std::cerr << "testing [" << program.f_expr << "]\n";
    3195           9 :             SNAP_CATCH2_NAMESPACE::reporter::lexer::pointer_t l(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::lexer>("invalid_modulos.rprtr", program.f_expr));
    3196           9 :             SNAP_CATCH2_NAMESPACE::reporter::state::pointer_t s(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::state>());
    3197           9 :             SNAP_CATCH2_NAMESPACE::reporter::parser::pointer_t p(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::parser>(l, s));
    3198           9 :             p->parse_program();
    3199             : 
    3200           9 :             CATCH_REQUIRE(s->get_statement_size() == 1);
    3201             : 
    3202           9 :             SNAP_CATCH2_NAMESPACE::reporter::executor::pointer_t e(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::executor>(s));
    3203           9 :             CATCH_REQUIRE_THROWS_MATCHES(
    3204             :                   e->start()
    3205             :                 , std::runtime_error
    3206             :                 , Catch::Matchers::ExceptionMessage(
    3207             :                           "unsupported modulo (types: "
    3208             :                         + std::to_string(static_cast<int>(program.f_lhs_token))
    3209             :                         + " and "
    3210             :                         + std::to_string(static_cast<int>(program.f_rhs_token))
    3211             :                         + ")."));
    3212           9 :         }
    3213             :     }
    3214          28 :     CATCH_END_SECTION()
    3215             : 
    3216          28 :     CATCH_START_SECTION("-<types> that are not valid")
    3217             :     {
    3218           1 :         constexpr char const * const bad_negations[] =
    3219             :         {
    3220             :             g_program_unsupported_negation_single_string,
    3221             :             g_program_unsupported_negation_double_string,
    3222             :             g_program_unsupported_negation_address,
    3223             :         };
    3224             : 
    3225           4 :         for(auto const & program : bad_negations)
    3226             :         {
    3227           3 :             SNAP_CATCH2_NAMESPACE::reporter::lexer::pointer_t l(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::lexer>("invalid_negate.rprtr", program));
    3228           3 :             SNAP_CATCH2_NAMESPACE::reporter::state::pointer_t s(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::state>());
    3229           3 :             SNAP_CATCH2_NAMESPACE::reporter::parser::pointer_t p(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::parser>(l, s));
    3230           3 :             p->parse_program();
    3231             : 
    3232           3 :             CATCH_REQUIRE(s->get_statement_size() == 1);
    3233             : 
    3234           3 :             SNAP_CATCH2_NAMESPACE::reporter::executor::pointer_t e(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::executor>(s));
    3235           3 :             CATCH_REQUIRE_THROWS_MATCHES(
    3236             :                   e->start()
    3237             :                 , std::runtime_error
    3238             :                 , Catch::Matchers::ExceptionMessage(
    3239             :                           "unsupported negation."));
    3240           3 :         }
    3241             :     }
    3242          28 :     CATCH_END_SECTION()
    3243             : 
    3244          28 :     CATCH_START_SECTION("variable reference without a '}'")
    3245             :     {
    3246           1 :         SNAP_CATCH2_NAMESPACE::reporter::lexer::pointer_t l(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::lexer>("invalid_negate.rprtr", g_program_unterminated_double_string_variable));
    3247           1 :         SNAP_CATCH2_NAMESPACE::reporter::state::pointer_t s(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::state>());
    3248           1 :         SNAP_CATCH2_NAMESPACE::reporter::parser::pointer_t p(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::parser>(l, s));
    3249           1 :         p->parse_program();
    3250             : 
    3251           1 :         CATCH_REQUIRE(s->get_statement_size() == 2);
    3252             : 
    3253           1 :         SNAP_CATCH2_NAMESPACE::reporter::executor::pointer_t e(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::executor>(s));
    3254           1 :         CATCH_REQUIRE_THROWS_MATCHES(
    3255             :               e->start()
    3256             :             , std::runtime_error
    3257             :             , Catch::Matchers::ExceptionMessage(
    3258             :                       "invalid_negate.rprtr:2: found unclosed variable in \"ref. ${my_var\"."));
    3259           1 :     }
    3260          28 :     CATCH_END_SECTION()
    3261             : 
    3262          28 :     CATCH_START_SECTION("regex variable in double string")
    3263             :     {
    3264           1 :         SNAP_CATCH2_NAMESPACE::reporter::lexer::pointer_t l(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::lexer>("invalid_negate.rprtr", g_program_regex_in_double_string_variable));
    3265           1 :         SNAP_CATCH2_NAMESPACE::reporter::state::pointer_t s(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::state>());
    3266           1 :         SNAP_CATCH2_NAMESPACE::reporter::parser::pointer_t p(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::parser>(l, s));
    3267           1 :         p->parse_program();
    3268             : 
    3269           1 :         CATCH_REQUIRE(s->get_statement_size() == 2);
    3270             : 
    3271           1 :         SNAP_CATCH2_NAMESPACE::reporter::executor::pointer_t e(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::executor>(s));
    3272           1 :         CATCH_REQUIRE_THROWS_MATCHES(
    3273             :               e->start()
    3274             :             , std::runtime_error
    3275             :             , Catch::Matchers::ExceptionMessage(
    3276             :                       "found variable of type \"regex\" which is not yet supported in ${...}."));
    3277           1 :     }
    3278          28 :     CATCH_END_SECTION()
    3279             : 
    3280          28 :     CATCH_START_SECTION("variable reference without a name")
    3281             :     {
    3282           1 :         SNAP_CATCH2_NAMESPACE::reporter::lexer::pointer_t l(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::lexer>("invalid_negate.rprtr", g_program_double_string_variable_without_name));
    3283           1 :         SNAP_CATCH2_NAMESPACE::reporter::state::pointer_t s(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::state>());
    3284           1 :         SNAP_CATCH2_NAMESPACE::reporter::parser::pointer_t p(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::parser>(l, s));
    3285           1 :         p->parse_program();
    3286             : 
    3287           1 :         CATCH_REQUIRE(s->get_statement_size() == 1);
    3288             : 
    3289           1 :         SNAP_CATCH2_NAMESPACE::reporter::executor::pointer_t e(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::executor>(s));
    3290           1 :         CATCH_REQUIRE_THROWS_MATCHES(
    3291             :               e->start()
    3292             :             , std::runtime_error
    3293             :             , Catch::Matchers::ExceptionMessage(
    3294             :                       "invalid_negate.rprtr:1: found variable without a name in \"ref. ${} is empty\"."));
    3295           1 :     }
    3296          28 :     CATCH_END_SECTION()
    3297             : 
    3298          28 :     CATCH_START_SECTION("<string> * <negative> is not valid")
    3299             :     {
    3300           1 :         SNAP_CATCH2_NAMESPACE::reporter::lexer::pointer_t l(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::lexer>("invalid_string_multiplication_negative.rprtr", g_program_unsupported_negation_repeat));
    3301           1 :         SNAP_CATCH2_NAMESPACE::reporter::state::pointer_t s(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::state>());
    3302           1 :         SNAP_CATCH2_NAMESPACE::reporter::parser::pointer_t p(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::parser>(l, s));
    3303           1 :         p->parse_program();
    3304             : 
    3305           1 :         CATCH_REQUIRE(s->get_statement_size() == 1);
    3306             : 
    3307           1 :         SNAP_CATCH2_NAMESPACE::reporter::executor::pointer_t e(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::executor>(s));
    3308           1 :         CATCH_REQUIRE_THROWS_MATCHES(
    3309             :               e->start()
    3310             :             , std::runtime_error
    3311             :             , Catch::Matchers::ExceptionMessage(
    3312             :                       "string repeat needs to be positive and under 1001."));
    3313           1 :     }
    3314          28 :     CATCH_END_SECTION()
    3315             : 
    3316          28 :     CATCH_START_SECTION("<string> * <large repeat> is not valid")
    3317             :     {
    3318           1 :         SNAP_CATCH2_NAMESPACE::reporter::lexer::pointer_t l(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::lexer>("invalid_string_multiplication_large.rprtr", g_program_unsupported_large_repeat));
    3319           1 :         SNAP_CATCH2_NAMESPACE::reporter::state::pointer_t s(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::state>());
    3320           1 :         SNAP_CATCH2_NAMESPACE::reporter::parser::pointer_t p(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::parser>(l, s));
    3321           1 :         p->parse_program();
    3322             : 
    3323           1 :         CATCH_REQUIRE(s->get_statement_size() == 1);
    3324             : 
    3325           1 :         SNAP_CATCH2_NAMESPACE::reporter::executor::pointer_t e(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::executor>(s));
    3326           1 :         CATCH_REQUIRE_THROWS_MATCHES(
    3327             :               e->start()
    3328             :             , std::runtime_error
    3329             :             , Catch::Matchers::ExceptionMessage(
    3330             :                       "string repeat needs to be positive and under 1001."));
    3331           1 :     }
    3332          28 :     CATCH_END_SECTION()
    3333             : 
    3334          28 :     CATCH_START_SECTION("exit() with timeout & error_message is invalid")
    3335             :     {
    3336           1 :         SNAP_CATCH2_NAMESPACE::reporter::lexer::pointer_t l(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::lexer>("bad_exit.rprtr", g_program_bad_exit));
    3337           1 :         SNAP_CATCH2_NAMESPACE::reporter::state::pointer_t s(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::state>());
    3338           1 :         SNAP_CATCH2_NAMESPACE::reporter::parser::pointer_t p(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::parser>(l, s));
    3339           1 :         p->parse_program();
    3340             : 
    3341           1 :         CATCH_REQUIRE(s->get_statement_size() == 1);
    3342             : 
    3343           1 :         SNAP_CATCH2_NAMESPACE::reporter::executor::pointer_t e(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::executor>(s));
    3344           1 :         CATCH_REQUIRE_THROWS_MATCHES(
    3345             :               e->start()
    3346             :             , std::runtime_error
    3347             :             , Catch::Matchers::ExceptionMessage(
    3348             :                       "\"timeout\" and \"error_message\" from the exit() instruction are mutually exclusive."));
    3349           1 :     }
    3350          28 :     CATCH_END_SECTION()
    3351             : 
    3352          28 :     CATCH_START_SECTION("exit() with timeout which is not a number")
    3353             :     {
    3354           1 :         SNAP_CATCH2_NAMESPACE::reporter::lexer::pointer_t l(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::lexer>("bad_exit.rprtr", g_program_bad_exit_timeout));
    3355           1 :         SNAP_CATCH2_NAMESPACE::reporter::state::pointer_t s(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::state>());
    3356           1 :         SNAP_CATCH2_NAMESPACE::reporter::parser::pointer_t p(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::parser>(l, s));
    3357           1 :         p->parse_program();
    3358             : 
    3359           1 :         CATCH_REQUIRE(s->get_statement_size() == 1);
    3360             : 
    3361           1 :         SNAP_CATCH2_NAMESPACE::reporter::executor::pointer_t e(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::executor>(s));
    3362           1 :         CATCH_REQUIRE_THROWS_MATCHES(
    3363             :               e->start()
    3364             :             , std::runtime_error
    3365             :             , Catch::Matchers::ExceptionMessage(
    3366             :                       "parameter type mismatch for timeout, expected \"number\", got \"string\" instead."));
    3367           1 :     }
    3368          28 :     CATCH_END_SECTION()
    3369             : 
    3370          28 :     CATCH_START_SECTION("exit() with timeout which is not a number")
    3371             :     {
    3372           1 :         SNAP_CATCH2_NAMESPACE::reporter::lexer::pointer_t l(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::lexer>("bad_print.rprtr", g_program_bad_print_message));
    3373           1 :         SNAP_CATCH2_NAMESPACE::reporter::state::pointer_t s(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::state>());
    3374           1 :         SNAP_CATCH2_NAMESPACE::reporter::parser::pointer_t p(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::parser>(l, s));
    3375           1 :         p->parse_program();
    3376             : 
    3377           1 :         CATCH_REQUIRE(s->get_statement_size() == 1);
    3378             : 
    3379           1 :         SNAP_CATCH2_NAMESPACE::reporter::executor::pointer_t e(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::executor>(s));
    3380           1 :         CATCH_REQUIRE_THROWS_MATCHES(
    3381             :               e->start()
    3382             :             , std::runtime_error
    3383             :             , Catch::Matchers::ExceptionMessage(
    3384             :                       "parameter type mismatch for message, expected \"string\", got \"identifier\" instead."));
    3385           1 :     }
    3386          28 :     CATCH_END_SECTION()
    3387             : 
    3388          28 :     CATCH_START_SECTION("send_message() when not connected")
    3389             :     {
    3390           1 :         SNAP_CATCH2_NAMESPACE::reporter::lexer::pointer_t l(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::lexer>("bad_send_message.rprtr", g_program_send_message_without_connection));
    3391           1 :         SNAP_CATCH2_NAMESPACE::reporter::state::pointer_t s(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::state>());
    3392           1 :         SNAP_CATCH2_NAMESPACE::reporter::parser::pointer_t p(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::parser>(l, s));
    3393           1 :         p->parse_program();
    3394             : 
    3395           1 :         CATCH_REQUIRE(s->get_statement_size() == 1);
    3396             : 
    3397           1 :         SNAP_CATCH2_NAMESPACE::reporter::executor::pointer_t e(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::executor>(s));
    3398           1 :         CATCH_REQUIRE_THROWS_MATCHES(
    3399             :               e->start()
    3400             :             , std::runtime_error
    3401             :             , Catch::Matchers::ExceptionMessage(
    3402             :                       "send_message() has no connection to send a message to."));
    3403           1 :     }
    3404          28 :     CATCH_END_SECTION()
    3405             : 
    3406          28 :     CATCH_START_SECTION("if(variable) with invalid type")
    3407             :     {
    3408           1 :         SNAP_CATCH2_NAMESPACE::reporter::lexer::pointer_t l(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::lexer>("if_invalid_type.rprtr", g_program_if_invalid_type));
    3409           1 :         SNAP_CATCH2_NAMESPACE::reporter::state::pointer_t s(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::state>());
    3410           1 :         SNAP_CATCH2_NAMESPACE::reporter::parser::pointer_t p(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::parser>(l, s));
    3411           1 :         p->parse_program();
    3412             : 
    3413           1 :         CATCH_REQUIRE(s->get_statement_size() == 5);
    3414             : 
    3415           1 :         SNAP_CATCH2_NAMESPACE::reporter::executor::pointer_t e(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::executor>(s));
    3416           1 :         CATCH_REQUIRE_THROWS_MATCHES(
    3417             :               e->start()
    3418             :             , std::runtime_error
    3419             :             , Catch::Matchers::ExceptionMessage(
    3420             :                       "if(variable: ...) only supports variables of type integer or floating point."));
    3421           1 :     }
    3422          28 :     CATCH_END_SECTION()
    3423             : 
    3424          28 :     CATCH_START_SECTION("wait() before starting thread")
    3425             :     {
    3426           1 :         SNAP_CATCH2_NAMESPACE::reporter::lexer::pointer_t l(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::lexer>("wait_outside_thread.rprtr", g_program_wait_outside_thread));
    3427           1 :         SNAP_CATCH2_NAMESPACE::reporter::state::pointer_t s(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::state>());
    3428           1 :         SNAP_CATCH2_NAMESPACE::reporter::parser::pointer_t p(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::parser>(l, s));
    3429           1 :         p->parse_program();
    3430             : 
    3431           1 :         CATCH_REQUIRE(s->get_statement_size() == 1);
    3432             : 
    3433           1 :         SNAP_CATCH2_NAMESPACE::reporter::executor::pointer_t e(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::executor>(s));
    3434           1 :         CATCH_REQUIRE_THROWS_MATCHES(
    3435             :               e->start()
    3436             :             , std::runtime_error
    3437             :             , Catch::Matchers::ExceptionMessage(
    3438             :                       "wait() used before run()."));
    3439           1 :     }
    3440          28 :     CATCH_END_SECTION()
    3441             : 
    3442          28 :     CATCH_START_SECTION("wait() with invalid mode")
    3443             :     {
    3444           1 :         SNAP_CATCH2_NAMESPACE::reporter::lexer::pointer_t l(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::lexer>("program_wait_invalid_mode.rprtr", g_program_wait_invalid_mode));
    3445           1 :         SNAP_CATCH2_NAMESPACE::reporter::state::pointer_t s(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::state>());
    3446           1 :         SNAP_CATCH2_NAMESPACE::reporter::parser::pointer_t p(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::parser>(l, s));
    3447           1 :         p->parse_program();
    3448             : 
    3449           1 :         CATCH_REQUIRE(s->get_statement_size() == 2);
    3450             : 
    3451           1 :         SNAP_CATCH2_NAMESPACE::reporter::executor::pointer_t e(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::executor>(s));
    3452           1 :         e->start();
    3453           1 :         addr::addr a;
    3454           1 :         sockaddr_in ip = {
    3455             :             .sin_family = AF_INET,
    3456           1 :             .sin_port = htons(20002),
    3457             :             .sin_addr = {
    3458           1 :                 .s_addr = htonl(0x7f000001),
    3459             :             },
    3460             :             .sin_zero = {},
    3461           1 :         };
    3462           1 :         a.set_ipv4(ip);
    3463           1 :         messenger_responder::pointer_t messenger(std::make_shared<messenger_responder>(
    3464             :                   a
    3465           1 :                 , ed::mode_t::MODE_PLAIN
    3466           2 :                 , messenger_responder::sequence_t::SEQUENCE_ONE_MESSAGE));
    3467           1 :         ed::communicator::instance()->add_connection(messenger);
    3468           1 :         messenger_timer::pointer_t timer(std::make_shared<messenger_timer>(messenger));
    3469           1 :         ed::communicator::instance()->add_connection(timer);
    3470           1 :         messenger->set_timer(timer);
    3471           1 :         e->set_thread_done_callback([messenger, timer]()
    3472             :             {
    3473           1 :                 ed::communicator::instance()->remove_connection(messenger);
    3474           1 :                 ed::communicator::instance()->remove_connection(timer);
    3475           1 :             });
    3476             : 
    3477           1 :         CATCH_REQUIRE(e->run());
    3478             : 
    3479             :         // the thread exception happens when e->stop() is called
    3480             :         //
    3481           1 :         CATCH_REQUIRE_THROWS_MATCHES(
    3482             :               e->stop()
    3483             :             , std::runtime_error
    3484             :             , Catch::Matchers::ExceptionMessage("program_wait_invalid_mode.rprtr:2: unknown mode \"not_this_one\" in wait()."));
    3485             : 
    3486             :         // if we exited because of our timer, then the test did not pass
    3487             :         //
    3488           1 :         CATCH_REQUIRE_FALSE(timer->timed_out_prima());
    3489             : 
    3490           1 :         CATCH_REQUIRE(s->get_exit_code() == -1);
    3491           1 :     }
    3492          28 :     CATCH_END_SECTION()
    3493             : 
    3494          28 :     CATCH_START_SECTION("wait() + drain without connections")
    3495             :     {
    3496           1 :         SNAP_CATCH2_NAMESPACE::reporter::lexer::pointer_t l(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::lexer>("program_wait_no_connection.rprtr", g_program_wait_no_connections));
    3497           1 :         SNAP_CATCH2_NAMESPACE::reporter::state::pointer_t s(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::state>());
    3498           1 :         SNAP_CATCH2_NAMESPACE::reporter::parser::pointer_t p(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::parser>(l, s));
    3499           1 :         p->parse_program();
    3500             : 
    3501           1 :         CATCH_REQUIRE(s->get_statement_size() == 2);
    3502             : 
    3503           1 :         SNAP_CATCH2_NAMESPACE::reporter::executor::pointer_t e(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::executor>(s));
    3504           1 :         e->start();
    3505           1 :         CATCH_REQUIRE(e->run());
    3506             : 
    3507             :         // the thread exception happens when e->stop() is called
    3508             :         //
    3509           1 :         CATCH_REQUIRE_THROWS_MATCHES(
    3510             :               e->stop()
    3511             :             , std::runtime_error
    3512             :             , Catch::Matchers::ExceptionMessage("no connections to wait() on."));
    3513             : 
    3514           1 :         CATCH_REQUIRE(s->get_exit_code() == -1);
    3515           1 :     }
    3516          28 :     CATCH_END_SECTION()
    3517             : 
    3518          28 :     CATCH_START_SECTION("try reading missing file")
    3519             :     {
    3520           1 :         std::string const source_dir(SNAP_CATCH2_NAMESPACE::g_source_dir());
    3521           1 :         std::string const filename(source_dir + "/tests/rprtr/not_this_one");
    3522           1 :         SNAP_CATCH2_NAMESPACE::reporter::lexer::pointer_t l(SNAP_CATCH2_NAMESPACE::reporter::create_lexer(filename));
    3523           1 :         CATCH_REQUIRE(l == nullptr);
    3524           1 :     }
    3525          28 :     CATCH_END_SECTION()
    3526             : 
    3527          28 :     CATCH_START_SECTION("verify that the executor::run() function does a try/catch as expected")
    3528             :     {
    3529             :         // in this case, load the program from a file
    3530             :         // to verify that this works as expected
    3531             :         //
    3532           1 :         std::string const source_dir(SNAP_CATCH2_NAMESPACE::g_source_dir());
    3533           1 :         std::string const filename(source_dir + "/tests/rprtr/send_and_receive_complete_messages");
    3534           1 :         SNAP_CATCH2_NAMESPACE::reporter::lexer::pointer_t l(SNAP_CATCH2_NAMESPACE::reporter::create_lexer(filename));
    3535           1 :         SNAP_CATCH2_NAMESPACE::reporter::state::pointer_t s(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::state>());
    3536           1 :         SNAP_CATCH2_NAMESPACE::reporter::parser::pointer_t p(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::parser>(l, s));
    3537           1 :         p->parse_program();
    3538             : 
    3539           1 :         CATCH_REQUIRE(s->get_statement_size() == 30);
    3540             : 
    3541           1 :         SNAP_CATCH2_NAMESPACE::reporter::executor::pointer_t e(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::executor>(s));
    3542           1 :         e->start();
    3543           1 :         addr::addr a;
    3544           1 :         sockaddr_in ip = {
    3545             :             .sin_family = AF_INET,
    3546           1 :             .sin_port = htons(20002),
    3547             :             .sin_addr = {
    3548           1 :                 .s_addr = htonl(0x7f000001),
    3549             :             },
    3550             :             .sin_zero = {},
    3551           1 :         };
    3552           1 :         a.set_ipv4(ip);
    3553           1 :         messenger_responder::pointer_t messenger(std::make_shared<messenger_responder>(
    3554             :                   a
    3555           1 :                 , ed::mode_t::MODE_PLAIN
    3556           2 :                 , messenger_responder::sequence_t::SEQUENCE_READY_THROW));
    3557           1 :         ed::communicator::instance()->add_connection(messenger);
    3558           1 :         messenger_timer::pointer_t timer(std::make_shared<messenger_timer>(messenger));
    3559           1 :         ed::communicator::instance()->add_connection(timer);
    3560           1 :         messenger->set_timer(timer);
    3561             : 
    3562             :         // the exception capture in run() is not returned; it should be
    3563             :         // printed in the console, making it possible to see what happened
    3564             :         //
    3565           1 :         CATCH_REQUIRE_FALSE(e->run());
    3566             : 
    3567           1 :         CATCH_REQUIRE_THROWS_MATCHES(
    3568             :               e->stop()
    3569             :             , std::runtime_error
    3570             :             , Catch::Matchers::ExceptionMessage("ppoll() timed out."));
    3571             : 
    3572             :         // if we exited because of our timer, then the test did not pass
    3573             :         //
    3574           1 :         CATCH_REQUIRE_FALSE(timer->timed_out_prima());
    3575             : 
    3576           1 :         CATCH_REQUIRE(s->get_exit_code() == -1);
    3577             : 
    3578             :         // in this case, the variable does not get unset because the
    3579             :         // crash happens before we have the chance to do that
    3580             :         //
    3581           3 :         SNAP_CATCH2_NAMESPACE::reporter::variable::pointer_t var(s->get_variable("got_register"));
    3582           1 :         CATCH_REQUIRE(var != nullptr);
    3583           1 :         CATCH_REQUIRE(var->get_type() == "integer");
    3584           1 :         CATCH_REQUIRE(std::static_pointer_cast<SNAP_CATCH2_NAMESPACE::reporter::variable_integer>(var)->get_integer() == 1);
    3585           1 :     }
    3586          28 :     CATCH_END_SECTION()
    3587             : 
    3588          28 :     CATCH_START_SECTION("verify that the executor::run() function does a try/catch of non-standard exceptions")
    3589             :     {
    3590             :         // in this case, load the program from a file
    3591             :         // to verify that this works as expected
    3592             :         //
    3593           1 :         std::string const source_dir(SNAP_CATCH2_NAMESPACE::g_source_dir());
    3594           1 :         std::string const filename(source_dir + "/tests/rprtr/send_and_receive_complete_messages");
    3595           1 :         SNAP_CATCH2_NAMESPACE::reporter::lexer::pointer_t l(SNAP_CATCH2_NAMESPACE::reporter::create_lexer(filename));
    3596           1 :         SNAP_CATCH2_NAMESPACE::reporter::state::pointer_t s(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::state>());
    3597           1 :         SNAP_CATCH2_NAMESPACE::reporter::parser::pointer_t p(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::parser>(l, s));
    3598           1 :         p->parse_program();
    3599             : 
    3600           1 :         CATCH_REQUIRE(s->get_statement_size() == 30);
    3601             : 
    3602           1 :         SNAP_CATCH2_NAMESPACE::reporter::executor::pointer_t e(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::executor>(s));
    3603           1 :         e->start();
    3604           1 :         addr::addr a;
    3605           1 :         sockaddr_in ip = {
    3606             :             .sin_family = AF_INET,
    3607           1 :             .sin_port = htons(20002),
    3608             :             .sin_addr = {
    3609           1 :                 .s_addr = htonl(0x7f000001),
    3610             :             },
    3611             :             .sin_zero = {},
    3612           1 :         };
    3613           1 :         a.set_ipv4(ip);
    3614           1 :         messenger_responder::pointer_t messenger(std::make_shared<messenger_responder>(
    3615             :                   a
    3616           1 :                 , ed::mode_t::MODE_PLAIN
    3617           2 :                 , messenger_responder::sequence_t::SEQUENCE_READY_THROW_WHAT));
    3618           1 :         ed::communicator::instance()->add_connection(messenger);
    3619           1 :         messenger_timer::pointer_t timer(std::make_shared<messenger_timer>(messenger));
    3620           1 :         ed::communicator::instance()->add_connection(timer);
    3621           1 :         messenger->set_timer(timer);
    3622             : 
    3623             :         // the exception capture in run() is not returned; it should be
    3624             :         // printed in the console, making it possible to see what happened
    3625             :         //
    3626           1 :         CATCH_REQUIRE_FALSE(e->run());
    3627             : 
    3628           1 :         CATCH_REQUIRE_THROWS_MATCHES(
    3629             :               e->stop()
    3630             :             , std::runtime_error
    3631             :             , Catch::Matchers::ExceptionMessage("ppoll() timed out."));
    3632             : 
    3633             :         // if we exited because of our timer, then the test did not pass
    3634             :         //
    3635           1 :         CATCH_REQUIRE_FALSE(timer->timed_out_prima());
    3636             : 
    3637           1 :         CATCH_REQUIRE(s->get_exit_code() == -1);
    3638             : 
    3639             :         // in this case, the variable does not get unset because the
    3640             :         // crash happens before we have the chance to do that
    3641             :         //
    3642           3 :         SNAP_CATCH2_NAMESPACE::reporter::variable::pointer_t var(s->get_variable("got_register"));
    3643           1 :         CATCH_REQUIRE(var != nullptr);
    3644           1 :         CATCH_REQUIRE(var->get_type() == "integer");
    3645           1 :         CATCH_REQUIRE(std::static_pointer_cast<SNAP_CATCH2_NAMESPACE::reporter::variable_integer>(var)->get_integer() == 1);
    3646           1 :     }
    3647          28 :     CATCH_END_SECTION()
    3648          28 : }
    3649             : 
    3650             : 
    3651           3 : CATCH_TEST_CASE("reporter_executor_error_message", "[executor][reporter][error]")
    3652             : {
    3653           3 :     CATCH_START_SECTION("verify message fails")
    3654             :     {
    3655             :         struct bad_verification_t
    3656             :         {
    3657             :             char const * const  f_program = nullptr;
    3658             :             char const * const  f_error = nullptr;
    3659             :         };
    3660           1 :         bad_verification_t const bad_verifications[] =
    3661             :         {
    3662             :             {
    3663             :                 g_program_verify_message_fail_sent_server,
    3664             :                 "program_verify_message_fail.rprtr:9: message expected \"sent_server\", set to \"\", to match \"not_this_one\".",
    3665             :             },
    3666             :             {
    3667             :                 g_program_verify_message_fail_sent_service,
    3668             :                 "program_verify_message_fail.rprtr:9: message expected \"sent_service\", set to \"\", to match \"not_this_one\".",
    3669             :             },
    3670             :             {
    3671             :                 g_program_verify_message_fail_server,
    3672             :                 "program_verify_message_fail.rprtr:9: message expected \"server\", set to \"\", to match \"not_this_one\".",
    3673             :             },
    3674             :             {
    3675             :                 g_program_verify_message_fail_service,
    3676             :                 "program_verify_message_fail.rprtr:9: message expected \"service\", set to \"\", to match \"not_this_one\".",
    3677             :             },
    3678             :             {
    3679             :                 g_program_verify_message_fail_command,
    3680             :                 "program_verify_message_fail.rprtr:9: message expected \"command\", set to \"REGISTER\", to match \"NOT_THIS_ONE\".",
    3681             :             },
    3682             :             {
    3683             :                 g_program_verify_message_fail_forbidden,
    3684             :                 "program_verify_message_fail.rprtr:9: message forbidden parameter \"version\" was found in this message.",
    3685             :             },
    3686             :             {
    3687             :                 g_program_verify_message_fail_required,
    3688             :                 "program_verify_message_fail.rprtr:9: message required parameter \"not_this_one\" was not found in this message.",
    3689             :             },
    3690             :             {
    3691             :                 g_program_verify_message_fail_required_int_value,
    3692             :                 "program_verify_message_fail.rprtr:9: message expected parameter \"version\" to be an integer set to \"200\" but found \"1\" instead.",
    3693             :             },
    3694             :             {
    3695             :                 g_program_verify_message_fail_required_str_value,
    3696             :                 "program_verify_message_fail.rprtr:9: message expected parameter \"service\" to be a string set to \"not_this_one\" but found \"responder\" instead.",
    3697             :             },
    3698             :             {
    3699             :                 g_program_verify_message_fail_required_flt_value,
    3700             :                 "program_verify_message_fail.rprtr:9: message parameter type \"floating_point\" not supported yet.",
    3701             :             },
    3702             :         };
    3703          11 :         for(auto const & bv : bad_verifications)
    3704             :         {
    3705          10 :             SNAP_CATCH2_NAMESPACE::reporter::lexer::pointer_t l(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::lexer>("program_verify_message_fail.rprtr", bv.f_program));
    3706          10 :             SNAP_CATCH2_NAMESPACE::reporter::state::pointer_t s(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::state>());
    3707          10 :             SNAP_CATCH2_NAMESPACE::reporter::parser::pointer_t p(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::parser>(l, s));
    3708          10 :             p->parse_program();
    3709             : 
    3710          10 :             SNAP_CATCH2_NAMESPACE::reporter::executor::pointer_t e(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::executor>(s));
    3711          10 :             e->start();
    3712          10 :             addr::addr a;
    3713          10 :             sockaddr_in ip = {
    3714             :                 .sin_family = AF_INET,
    3715          10 :                 .sin_port = htons(20002),
    3716             :                 .sin_addr = {
    3717          10 :                     .s_addr = htonl(0x7f000001),
    3718             :                 },
    3719             :                 .sin_zero = {},
    3720          10 :             };
    3721          10 :             a.set_ipv4(ip);
    3722          10 :             messenger_responder::pointer_t messenger(std::make_shared<messenger_responder>(
    3723             :                       a
    3724          10 :                     , ed::mode_t::MODE_PLAIN
    3725          20 :                     , messenger_responder::sequence_t::SEQUENCE_ONE_MESSAGE));
    3726          10 :             ed::communicator::instance()->add_connection(messenger);
    3727          10 :             messenger_timer::pointer_t timer(std::make_shared<messenger_timer>(messenger));
    3728          10 :             ed::communicator::instance()->add_connection(timer);
    3729          10 :             messenger->set_timer(timer);
    3730          10 :             e->set_thread_done_callback([messenger, timer]()
    3731             :                 {
    3732          10 :                     ed::communicator::instance()->remove_connection(messenger);
    3733          10 :                     ed::communicator::instance()->remove_connection(timer);
    3734          10 :                 });
    3735             : 
    3736          10 :             CATCH_REQUIRE(e->run());
    3737             : 
    3738             :             // the thread exception happens when e->stop() is called
    3739             :             //
    3740          10 :             CATCH_REQUIRE_THROWS_MATCHES(
    3741             :                   e->stop()
    3742             :                 , std::runtime_error
    3743             :                 , Catch::Matchers::ExceptionMessage(bv.f_error));
    3744             : 
    3745             :             // if we exited because of our timer, then the test did not pass
    3746             :             //
    3747          10 :             CATCH_REQUIRE_FALSE(timer->timed_out_prima());
    3748             : 
    3749          10 :             CATCH_REQUIRE(s->get_exit_code() == -1);
    3750          10 :         }
    3751             :     }
    3752           3 :     CATCH_END_SECTION()
    3753             : 
    3754           3 :     CATCH_START_SECTION("wait for nothing (should time out)")
    3755             :     {
    3756           1 :         SNAP_CATCH2_NAMESPACE::reporter::lexer::pointer_t l(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::lexer>("program_wait_for_nothing.rprtr", g_program_wait_for_nothing));
    3757           1 :         SNAP_CATCH2_NAMESPACE::reporter::state::pointer_t s(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::state>());
    3758           1 :         SNAP_CATCH2_NAMESPACE::reporter::parser::pointer_t p(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::parser>(l, s));
    3759           1 :         p->parse_program();
    3760             : 
    3761           1 :         SNAP_CATCH2_NAMESPACE::reporter::executor::pointer_t e(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::executor>(s));
    3762           1 :         e->start();
    3763           1 :         addr::addr a;
    3764           1 :         sockaddr_in ip = {
    3765             :             .sin_family = AF_INET,
    3766           1 :             .sin_port = htons(20002),
    3767             :             .sin_addr = {
    3768           1 :                 .s_addr = htonl(0x7f000001),
    3769             :             },
    3770             :             .sin_zero = {},
    3771           1 :         };
    3772           1 :         a.set_ipv4(ip);
    3773           1 :         messenger_responder::pointer_t messenger(std::make_shared<messenger_responder>(
    3774             :                   a
    3775           1 :                 , ed::mode_t::MODE_PLAIN
    3776           2 :                 , messenger_responder::sequence_t::SEQUENCE_ONE_MESSAGE));
    3777           1 :         ed::communicator::instance()->add_connection(messenger);
    3778           1 :         messenger_timer::pointer_t timer(std::make_shared<messenger_timer>(messenger));
    3779           1 :         ed::communicator::instance()->add_connection(timer);
    3780           1 :         messenger->set_timer(timer);
    3781           1 :         e->set_thread_done_callback([messenger, timer]()
    3782             :             {
    3783           1 :                 ed::communicator::instance()->remove_connection(messenger);
    3784           1 :                 ed::communicator::instance()->remove_connection(timer);
    3785           1 :             });
    3786           1 :         CATCH_REQUIRE(e->run());
    3787             : 
    3788           1 :         CATCH_REQUIRE_THROWS_MATCHES(
    3789             :               e->stop()
    3790             :             , std::runtime_error
    3791             :             , Catch::Matchers::ExceptionMessage("ppoll() timed out."));
    3792             : 
    3793             :         // if we exited because of our timer, then the test did not pass
    3794             :         //
    3795           1 :         CATCH_REQUIRE_FALSE(timer->timed_out_prima());
    3796             : 
    3797           1 :         CATCH_REQUIRE(s->get_exit_code() == -1);
    3798           1 :     }
    3799           3 :     CATCH_END_SECTION()
    3800             : 
    3801           3 :     CATCH_START_SECTION("check parameter with incorrect regex fails")
    3802             :     {
    3803           1 :         SNAP_CATCH2_NAMESPACE::reporter::lexer::pointer_t l(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::lexer>("program_regex_parameter_no_match.rprtr", g_program_regex_parameter_no_match));
    3804           1 :         SNAP_CATCH2_NAMESPACE::reporter::state::pointer_t s(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::state>());
    3805           1 :         SNAP_CATCH2_NAMESPACE::reporter::parser::pointer_t p(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::parser>(l, s));
    3806           1 :         p->parse_program();
    3807             : 
    3808           1 :         SNAP_CATCH2_NAMESPACE::reporter::executor::pointer_t e(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::executor>(s));
    3809           1 :         e->start();
    3810           1 :         addr::addr a;
    3811           1 :         sockaddr_in ip = {
    3812             :             .sin_family = AF_INET,
    3813           1 :             .sin_port = htons(20002),
    3814             :             .sin_addr = {
    3815           1 :                 .s_addr = htonl(0x7f000001),
    3816             :             },
    3817             :             .sin_zero = {},
    3818           1 :         };
    3819           1 :         a.set_ipv4(ip);
    3820           1 :         messenger_responder::pointer_t messenger(std::make_shared<messenger_responder>(
    3821             :                   a
    3822           1 :                 , ed::mode_t::MODE_PLAIN
    3823           2 :                 , messenger_responder::sequence_t::SEQUENCE_ONE_MESSAGE));
    3824           1 :         ed::communicator::instance()->add_connection(messenger);
    3825           1 :         messenger_timer::pointer_t timer(std::make_shared<messenger_timer>(messenger));
    3826           1 :         ed::communicator::instance()->add_connection(timer);
    3827           1 :         messenger->set_timer(timer);
    3828           1 :         e->set_thread_done_callback([messenger, timer]()
    3829             :             {
    3830           1 :                 ed::communicator::instance()->remove_connection(messenger);
    3831           1 :                 ed::communicator::instance()->remove_connection(timer);
    3832           1 :             });
    3833           1 :         CATCH_REQUIRE(e->run());
    3834             : 
    3835           1 :         CATCH_REQUIRE_THROWS_MATCHES(
    3836             :               e->stop()
    3837             :             , std::runtime_error
    3838             :             , Catch::Matchers::ExceptionMessage("program_regex_parameter_no_match.rprtr:9: message expected parameter \"version\", set to \"1\", to match regex \"_[a-z]+\"."));
    3839             : 
    3840             :         // if we exited because of our timer, then the test did not pass
    3841             :         //
    3842           1 :         CATCH_REQUIRE_FALSE(timer->timed_out_prima());
    3843             : 
    3844           1 :         CATCH_REQUIRE(s->get_exit_code() == -1);
    3845           1 :     }
    3846           3 :     CATCH_END_SECTION()
    3847           3 : }
    3848             : 
    3849             : 
    3850             : 
    3851             : // vim: ts=4 sw=4 et

Generated by: LCOV version 1.14

Snap C++ | List of projects | List of versions