Line data Source code
1 : /* 2 : This file is part of TALER 3 : Copyright (C) 2014-2020 Taler Systems SA 4 : 5 : TALER is free software; you can redistribute it and/or modify 6 : it under the terms of the GNU General Public License as 7 : published by the Free Software Foundation; either version 3, or 8 : (at your option) any later version. 9 : 10 : TALER is distributed in the hope that it will be useful, but 11 : WITHOUT ANY WARRANTY; without even the implied warranty of 12 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 : GNU General Public License for more details. 14 : 15 : You should have received a copy of the GNU General Public 16 : License along with TALER; see the file COPYING. If not, see 17 : <http://www.gnu.org/licenses/> 18 : */ 19 : /** 20 : * @file testing/testing_api_cmd_rewind.c 21 : * @brief command to rewind the instruction pointer. 22 : * @author Marcello Stanisci 23 : * @author Christian Grothoff 24 : */ 25 : #include "platform.h" 26 : #include "taler_exchange_service.h" 27 : #include "taler_testing_lib.h" 28 : 29 : 30 : /** 31 : * State for a "rewind" CMD. 32 : */ 33 : struct RewindIpState 34 : { 35 : /** 36 : * Instruction pointer to set into the interpreter. 37 : */ 38 : const char *target_label; 39 : 40 : /** 41 : * How many times this set should take place. However, this value lives at 42 : * the calling process, and this CMD is only in charge of checking and 43 : * decremeting it. 44 : */ 45 : unsigned int counter; 46 : }; 47 : 48 : 49 : /** 50 : * Seek for the @a target command in @a batch (and rewind to it 51 : * if successful). 52 : * 53 : * @param is the interpreter state (for failures) 54 : * @param cmd batch to search for @a target 55 : * @param target command to search for 56 : * @return #GNUNET_OK on success, #GNUNET_NO if target was not found, 57 : * #GNUNET_SYSERR if target is in the future and we failed 58 : */ 59 : static enum GNUNET_GenericReturnValue 60 0 : seek_batch (struct TALER_TESTING_Interpreter *is, 61 : const struct TALER_TESTING_Command *cmd, 62 : const struct TALER_TESTING_Command *target) 63 : { 64 : unsigned int new_ip; 65 : struct TALER_TESTING_Command **batch; 66 : struct TALER_TESTING_Command *current; 67 : struct TALER_TESTING_Command *icmd; 68 : struct TALER_TESTING_Command *match; 69 : 70 0 : current = TALER_TESTING_cmd_batch_get_current (cmd); 71 0 : GNUNET_assert (GNUNET_OK == 72 : TALER_TESTING_get_trait_batch_cmds (cmd, 73 : &batch)); 74 0 : match = NULL; 75 0 : for (new_ip = 0; 76 0 : NULL != (icmd = &(*batch)[new_ip]); 77 0 : new_ip++) 78 : { 79 0 : if (current == target) 80 0 : current = NULL; 81 0 : if (icmd == target) 82 : { 83 0 : match = icmd; 84 0 : break; 85 : } 86 0 : if (TALER_TESTING_cmd_is_batch (icmd)) 87 : { 88 0 : int ret = seek_batch (is, 89 : icmd, 90 : target); 91 0 : if (GNUNET_SYSERR == ret) 92 0 : return GNUNET_SYSERR; /* failure! */ 93 0 : if (GNUNET_OK == ret) 94 : { 95 0 : match = icmd; 96 0 : break; 97 : } 98 : } 99 : } 100 0 : if (NULL == current) 101 : { 102 : /* refuse to jump forward */ 103 0 : GNUNET_break (0); 104 0 : TALER_TESTING_interpreter_fail (is); 105 0 : return GNUNET_SYSERR; 106 : } 107 0 : if (NULL == match) 108 0 : return GNUNET_NO; /* not found */ 109 0 : TALER_TESTING_cmd_batch_set_current (cmd, 110 : new_ip); 111 0 : return GNUNET_OK; 112 : } 113 : 114 : 115 : /** 116 : * Run the "rewind" CMD. 117 : * 118 : * @param cls closure. 119 : * @param cmd command being executed now. 120 : * @param is the interpreter state. 121 : */ 122 : static void 123 0 : rewind_ip_run (void *cls, 124 : const struct TALER_TESTING_Command *cmd, 125 : struct TALER_TESTING_Interpreter *is) 126 : { 127 0 : struct RewindIpState *ris = cls; 128 : const struct TALER_TESTING_Command *target; 129 : unsigned int new_ip; 130 : 131 : (void) cmd; 132 0 : if (0 == ris->counter) 133 : { 134 0 : TALER_TESTING_interpreter_next (is); 135 0 : return; 136 : } 137 : target 138 0 : = TALER_TESTING_interpreter_lookup_command (is, 139 : ris->target_label); 140 0 : if (NULL == target) 141 : { 142 0 : GNUNET_break (0); 143 0 : TALER_TESTING_interpreter_fail (is); 144 0 : return; 145 : } 146 0 : ris->counter--; 147 0 : for (new_ip = 0; 148 0 : NULL != is->commands[new_ip].label; 149 0 : new_ip++) 150 : { 151 0 : const struct TALER_TESTING_Command *cmd = &is->commands[new_ip]; 152 : 153 0 : if (cmd == target) 154 0 : break; 155 0 : if (TALER_TESTING_cmd_is_batch (cmd)) 156 : { 157 0 : int ret = seek_batch (is, 158 : cmd, 159 : target); 160 0 : if (GNUNET_SYSERR == ret) 161 0 : return; /* failure! */ 162 0 : if (GNUNET_OK == ret) 163 0 : break; 164 : } 165 : } 166 0 : if (new_ip > (unsigned int) is->ip) 167 : { 168 : /* refuse to jump forward */ 169 0 : GNUNET_break (0); 170 0 : TALER_TESTING_interpreter_fail (is); 171 0 : return; 172 : } 173 0 : is->ip = new_ip - 1; /* -1 because the next function will advance by one */ 174 0 : TALER_TESTING_interpreter_next (is); 175 : } 176 : 177 : 178 : struct TALER_TESTING_Command 179 0 : TALER_TESTING_cmd_rewind_ip (const char *label, 180 : const char *target_label, 181 : unsigned int counter) 182 : { 183 : struct RewindIpState *ris; 184 : 185 0 : ris = GNUNET_new (struct RewindIpState); 186 0 : ris->target_label = target_label; 187 0 : ris->counter = counter; 188 : { 189 0 : struct TALER_TESTING_Command cmd = { 190 : .cls = ris, 191 : .label = label, 192 : .run = &rewind_ip_run 193 : }; 194 : 195 0 : return cmd; 196 : } 197 : }