From 49f466df401259248c5d187374655492d4b4eec7 Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Fri, 3 Jul 2020 20:57:01 +0200 Subject: move rewind command to exchange, add proper support for rewinding in batches, modify API to rewind to label --- src/testing/testing_api_cmd_rewind.c | 222 +++++++++++++++++++++++++++++++++++ 1 file changed, 222 insertions(+) create mode 100644 src/testing/testing_api_cmd_rewind.c (limited to 'src/testing/testing_api_cmd_rewind.c') diff --git a/src/testing/testing_api_cmd_rewind.c b/src/testing/testing_api_cmd_rewind.c new file mode 100644 index 000000000..cde966d7f --- /dev/null +++ b/src/testing/testing_api_cmd_rewind.c @@ -0,0 +1,222 @@ +/* + This file is part of TALER + Copyright (C) 2014-2020 Taler Systems SA + + TALER is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 3, or + (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public + License along with TALER; see the file COPYING. If not, see + +*/ +/** + * @file testing/testing_api_cmd_rewind.c + * @brief command to rewind the instruction pointer. + * @author Marcello Stanisci + * @author Christian Grothoff + */ +#include "platform.h" +#include +#include +#include "taler_testing_lib.h" + + +/** + * State for a "rewind" CMD. + */ +struct RewindIpState +{ + /** + * Instruction pointer to set into the interpreter. + */ + const char *target_label; + + /** + * How many times this set should take place. However, this value lives at + * the calling process, and this CMD is only in charge of checking and + * decremeting it. + */ + unsigned int counter; +}; + + +/** + * Only defined to respect the API. + */ +static void +rewind_ip_cleanup (void *cls, + const struct TALER_TESTING_Command *cmd) +{ + (void) cls; + (void) cmd; +} + + +/** + * Seek for the @a target command in @a batch (and rewind to it + * if successful). + * + * @param is the interpreter state (for failures) + * @param cmd batch to search for @a target + * @param target command to search for + * @return #GNUNET_OK on success, #GNUNET_NO if target was not found, + * #GNUNET_SYSERR if target is in the future and we failed + */ +static int +seek_batch (struct TALER_TESTING_Interpreter *is, + const struct TALER_TESTING_Command *cmd, + const struct TALER_TESTING_Command *target) +{ + unsigned int new_ip; +#define BATCH_INDEX 1 + struct TALER_TESTING_Command *batch; + struct TALER_TESTING_Command *current; + struct TALER_TESTING_Command *icmd; + const struct TALER_TESTING_Command *match; + + current = TALER_TESTING_cmd_batch_get_current (cmd); + GNUNET_assert (GNUNET_OK == + TALER_TESTING_get_trait_cmd (cmd, + BATCH_INDEX, + &batch)); + match = NULL; + for (new_ip = 0; + NULL != (icmd = &batch[new_ip]); + new_ip++) + { + if (current == target) + current = NULL; + if (icmd == target) + { + match = icmd; + break; + } + if (TALER_TESTING_cmd_is_batch (icmd)) + { + int ret = seek_batch (is, + icmd, + target); + if (GNUNET_SYSERR == ret) + return GNUNET_SYSERR; /* failure! */ + if (GNUNET_OK == ret) + { + match = icmd; + break; + } + } + } + if (NULL == current) + { + /* refuse to jump forward */ + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return GNUNET_SYSERR; + } + if (NULL == match) + return GNUNET_NO; /* not found */ + TALER_TESTING_cmd_batch_set_current (cmd, + new_ip); + return GNUNET_OK; +} + + +/** + * Run the "rewind" CMD. + * + * @param cls closure. + * @param cmd command being executed now. + * @param is the interpreter state. + */ +static void +rewind_ip_run (void *cls, + const struct TALER_TESTING_Command *cmd, + struct TALER_TESTING_Interpreter *is) +{ + struct RewindIpState *ris = cls; + const struct TALER_TESTING_Command *target; + unsigned int new_ip; + + (void) cmd; + if (0 == ris->counter) + { + TALER_TESTING_interpreter_next (is); + return; + } + target + = TALER_TESTING_interpreter_lookup_command (is, + ris->target_label); + if (NULL == target) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return; + } + ris->counter--; + for (new_ip = 0; + NULL != is->commands[new_ip].label; + new_ip++) + { + const struct TALER_TESTING_Command *cmd = &is->commands[new_ip]; + + if (cmd == target) + break; + if (TALER_TESTING_cmd_is_batch (cmd)) + { + int ret = seek_batch (is, + cmd, + target); + if (GNUNET_SYSERR == ret) + return; /* failure! */ + if (GNUNET_OK == ret) + break; + } + } + if (new_ip > is->ip) + { + /* refuse to jump forward */ + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return; + } + is->ip = new_ip - 1; /* -1 because the next function will advance by one */ + TALER_TESTING_interpreter_next (is); +} + + +/** + * Make the instruction pointer point to @a new_ip + * only if @a counter is greater than zero. + * + * @param label command label + * @param target_label label of the new instruction pointer's destination after the jump; + * must be before the current instruction + * @param counter counts how many times the rewinding is to happen. + */ +struct TALER_TESTING_Command +TALER_TESTING_cmd_rewind_ip (const char *label, + const char *target_label, + unsigned int counter) +{ + struct RewindIpState *ris; + + ris = GNUNET_new (struct RewindIpState); + ris->target_label = target_label; + ris->counter = counter; + { + struct TALER_TESTING_Command cmd = { + .cls = ris, + .label = label, + .run = &rewind_ip_run, + .cleanup = &rewind_ip_cleanup + }; + + return cmd; + } +} -- cgit v1.2.3