diff --git a/compiler2/ttcn3/Statement.cc b/compiler2/ttcn3/Statement.cc index 1ddf88d11610365e4b2e32d5d8b76727e0a1f4e7..37c8ef4f8a127e06af2be71bd6059f6365b5a2ec 100644 --- a/compiler2/ttcn3/Statement.cc +++ b/compiler2/ttcn3/Statement.cc @@ -4775,9 +4775,9 @@ error: comp_op.donereturn.redirect->chk(return_type); } } else if (comp_op.donereturn.redirect) { - comp_op.donereturn.redirect->error("Redirect cannot be used for the " - "return value without a matching template"); - comp_op.donereturn.redirect->chk_erroneous(); + // if there is no matching template, then the value redirect stores the + // PTC's verdict instead of the return value + comp_op.donereturn.redirect->chk_verdict_only(); } if (comp_op.index_redirect != NULL && ref_type != NULL) { ArrayDimensions dummy; @@ -8161,41 +8161,41 @@ error: { if (comp_op.compref) { if (comp_op.donereturn.donematch) { - // value returning done - // figure out what type the done() function belongs to - Type *t = comp_op.donereturn.donematch - ->get_expr_governor(Type::EXPECTED_TEMPLATE); - if (!t) FATAL_ERROR("Statement::generate_code_expr_done()"); - while (t->is_ref() && !t->has_done_attribute()) - t = t->get_type_refd(); - if (!t->has_done_attribute()) - FATAL_ERROR("Statement::generate_code_expr_done()"); - // determine whether the done() function is in the same module - Common::Module *t_mod = t->get_my_scope()->get_scope_mod_gen(); - if (t_mod != my_sb->get_scope_mod_gen()) { - expr->expr = mputprintf(expr->expr, "%s::", - t_mod->get_modid().get_name().c_str()); - } - expr->expr = mputstr(expr->expr, "done("); - comp_op.compref->generate_code_expr(expr); - expr->expr = mputstr(expr->expr, ", "); - bool has_decoded_redirect = comp_op.donereturn.redirect != NULL && - comp_op.donereturn.redirect->has_decoded_modifier(); - comp_op.donereturn.donematch->generate_code(expr, TR_NONE, has_decoded_redirect); - expr->expr = mputstr(expr->expr, ", "); - if (comp_op.donereturn.redirect) { - // value redirect is present - comp_op.donereturn.redirect->generate_code(expr, comp_op.donereturn.donematch); - } else { - // value redirect is omitted - expr->expr = mputstr(expr->expr, "NULL"); - } - expr->expr = mputstr(expr->expr, ", "); + // value returning done + // figure out what type the done() function belongs to + Type *t = comp_op.donereturn.donematch + ->get_expr_governor(Type::EXPECTED_TEMPLATE); + if (!t) FATAL_ERROR("Statement::generate_code_expr_done()"); + while (t->is_ref() && !t->has_done_attribute()) + t = t->get_type_refd(); + if (!t->has_done_attribute()) + FATAL_ERROR("Statement::generate_code_expr_done()"); + // determine whether the done() function is in the same module + Common::Module *t_mod = t->get_my_scope()->get_scope_mod_gen(); + if (t_mod != my_sb->get_scope_mod_gen()) { + expr->expr = mputprintf(expr->expr, "%s::", + t_mod->get_modid().get_name().c_str()); + } + expr->expr = mputstr(expr->expr, "done("); + comp_op.compref->generate_code_expr(expr); + expr->expr = mputstr(expr->expr, ", "); + bool has_decoded_redirect = comp_op.donereturn.redirect != NULL && + comp_op.donereturn.redirect->has_decoded_modifier(); + comp_op.donereturn.donematch->generate_code(expr, TR_NONE, has_decoded_redirect); + expr->expr = mputstr(expr->expr, ", "); + } else { + // simple done + comp_op.compref->generate_code_expr_mandatory(expr); + expr->expr = mputstr(expr->expr, ".done("); + } + if (comp_op.donereturn.redirect != NULL) { + // value redirect is present + comp_op.donereturn.redirect->generate_code(expr, comp_op.donereturn.donematch); } else { - // simple done - comp_op.compref->generate_code_expr_mandatory(expr); - expr->expr = mputstr(expr->expr, ".done("); + // value redirect is omitted + expr->expr = mputstr(expr->expr, "NULL"); } + expr->expr = mputstr(expr->expr, ", "); if (comp_op.index_redirect != NULL) { generate_code_index_redirect(expr, comp_op.index_redirect, my_sb); } @@ -10262,13 +10262,14 @@ error: bool ValueRedirect::chk_RT1_restrictions() const { if (v.size() > 1) { - error("Redirecting multiple values is not supported in the Load Test " - "Runtime."); + error(verdict_only ? "Only one redirect is allowed in this case." : + "Redirecting multiple values is not supported in the Load Test Runtime."); return false; } if (v[0]->get_subrefs() != NULL) { - error("Redirecting parts of a value is not supported in the Load Test " - "Runtime."); + error(verdict_only ? "Cannot apply field names or array indexes to a " + "variable of type `verdicttype'." : + "Redirecting parts of a value is not supported in the Load Test Runtime."); return false; } return true; @@ -10290,9 +10291,15 @@ error: } } + void ValueRedirect::chk_verdict_only() + { + verdict_only = true; + chk(Type::get_pooltype(Type::T_VERDICT)); + } + void ValueRedirect::chk(Type* p_type) { - if (!use_runtime_2 && !chk_RT1_restrictions()) { + if ((verdict_only || !use_runtime_2) && !chk_RT1_restrictions()) { return; } bool invalid_type = p_type->get_typetype() == Type::T_ERROR; @@ -10370,7 +10377,7 @@ error: exp_type = p_type; } if (exp_type != NULL && var_type != NULL) { - if (use_runtime_2) { + if (use_runtime_2 && !verdict_only) { // check for type compatibility in RT2 TypeCompatInfo info(v[i]->get_var_ref()->get_my_scope()->get_scope_mod(), exp_type, var_type, true, false); @@ -10407,7 +10414,7 @@ error: void ValueRedirect::generate_code(expression_struct* expr, TemplateInstance* matched_ti) { - if (use_runtime_2) { + if (use_runtime_2 && !verdict_only) { // a value redirect class is generated for this redirect in the expression's // preamble and instantiated in the expression Scope* scope = v[0]->get_var_ref()->get_my_scope(); @@ -10980,7 +10987,7 @@ error: Free(inst_params_str); expr->expr = mputprintf(expr->expr, "&%s", instance_id.c_str()); } - else { // RT1 + else { // RT1 or verdict only // in this case only the address of the one variable needs to be generated expr->expr = mputstr(expr->expr, "&("); v[0]->get_var_ref()->generate_code(expr); diff --git a/compiler2/ttcn3/Statement.hh b/compiler2/ttcn3/Statement.hh index 3bb62caad013df558cb13395bb75210d046905f4..d77479586988c4ea97414d568faf1f5d22a55654 100644 --- a/compiler2/ttcn3/Statement.hh +++ b/compiler2/ttcn3/Statement.hh @@ -1187,11 +1187,14 @@ namespace Ttcn { vector<SingleValueRedirect> v; /** pointer to the type of the redirected value, not owned */ Type* value_type; + /** indicates whether the value redirect is restricted to only one value of + * type 'verdicttype' */ + bool verdict_only; ValueRedirect(const ValueRedirect&); ValueRedirect& operator=(const ValueRedirect&); public: - ValueRedirect(): v(), value_type(NULL) { } + ValueRedirect(): v(), value_type(NULL), verdict_only(false) { } virtual ~ValueRedirect(); virtual ValueRedirect* clone() const; virtual void set_my_scope(Scope* p_scope); @@ -1209,6 +1212,10 @@ namespace Ttcn { * type of the redirected value. Called when the value's type cannot be * determined or is erroneous. */ void chk_erroneous(); + /** Performs the full semantic analysis on the value redirect. + * Only used by the 'done' statement, when it can only redirect a value of + * type 'verdicttype'. */ + void chk_verdict_only(); /** Performs the full semantic analysis on the value redirect. * @param p_type the type of the redirected value */ void chk(Type* p_type); diff --git a/core/Array.hh b/core/Array.hh index 62fc25c9e84efc172757cbbac5896b71804aa63f..006d5d0815dc2c3ffbb4bb2a4a59e3ba5c614dcd 100644 --- a/core/Array.hh +++ b/core/Array.hh @@ -970,14 +970,14 @@ public: int JSON_decode(const TTCN_Typedescriptor_t&, JSON_Tokenizer&, boolean); // alt-status priority: ALT_YES (return immediately) > ALT_REPEAT > ALT_MAYBE > ALT_NO - alt_status done(Index_Redirect* index_redirect) const + alt_status done(VERDICTTYPE* value_redirect, Index_Redirect* index_redirect) const { if (index_redirect != NULL) { index_redirect->incr_pos(); } alt_status result = ALT_NO; for (unsigned int i = 0; i < array_size; ++i) { - alt_status ret_val = array_elements[i].done(index_redirect); + alt_status ret_val = array_elements[i].done(value_redirect, index_redirect); if (ret_val == ALT_YES) { if (index_redirect != NULL) { index_redirect->add_index((int)i + index_offset); diff --git a/core/Communication.cc b/core/Communication.cc index 34ed422203dfb49fb8b36de42c48f8a8e6a1ba81..f96b36ee2dfc3d2bc9279d18decf52174a1b9cd1 100644 --- a/core/Communication.cc +++ b/core/Communication.cc @@ -1512,12 +1512,14 @@ void TTCN_Communication::process_done_ack(int msg_end) { // decoding the mandatory attributes boolean answer = incoming_buf.pull_int().get_val(); + verdicttype ptc_verdict = static_cast<verdicttype>( + incoming_buf.pull_int().get_val()); char *return_type = incoming_buf.pull_string(); // the return value starts here int return_value_begin = incoming_buf.get_pos(); try { - TTCN_Runtime::process_done_ack(answer, return_type, + TTCN_Runtime::process_done_ack(answer, ptc_verdict, return_type, msg_end - return_value_begin, incoming_buf.get_data() + return_value_begin); } catch (...) { @@ -1567,12 +1569,14 @@ void TTCN_Communication::process_component_status_mtc(int msg_end) boolean is_any_killed = incoming_buf.pull_int().get_val(); boolean is_all_killed = incoming_buf.pull_int().get_val(); if (is_done) { - // the return type and value is valid + // the return type and value are valid + verdicttype ptc_verdict = static_cast<verdicttype>( + incoming_buf.pull_int().get_val()); char *return_type = incoming_buf.pull_string(); int return_value_begin = incoming_buf.get_pos(); try { - TTCN_Runtime::set_component_done(component_reference, return_type, - msg_end - return_value_begin, + TTCN_Runtime::set_component_done(component_reference, ptc_verdict, + return_type, msg_end - return_value_begin, incoming_buf.get_data() + return_value_begin); } catch (...) { // avoid memory leaks @@ -1584,9 +1588,9 @@ void TTCN_Communication::process_component_status_mtc(int msg_end) } if (is_killed) TTCN_Runtime::set_component_killed(component_reference); if (is_any_done) - TTCN_Runtime::set_component_done(ANY_COMPREF, NULL, 0, NULL); + TTCN_Runtime::set_component_done(ANY_COMPREF, NONE, NULL, 0, NULL); if (is_all_done) - TTCN_Runtime::set_component_done(ALL_COMPREF, NULL, 0, NULL); + TTCN_Runtime::set_component_done(ALL_COMPREF, NONE, NULL, 0, NULL); if (is_any_killed) TTCN_Runtime::set_component_killed(ANY_COMPREF); if (is_all_killed) TTCN_Runtime::set_component_killed(ALL_COMPREF); incoming_buf.cut_message(); @@ -1604,11 +1608,13 @@ void TTCN_Communication::process_component_status_ptc(int msg_end) boolean is_killed = incoming_buf.pull_int().get_val(); if (is_done) { // the return type and value is valid + verdicttype ptc_verdict = static_cast<verdicttype>( + incoming_buf.pull_int().get_val()); char *return_type = incoming_buf.pull_string(); int return_value_begin = incoming_buf.get_pos(); try { - TTCN_Runtime::set_component_done(component_reference, return_type, - msg_end - return_value_begin, + TTCN_Runtime::set_component_done(component_reference, ptc_verdict, + return_type, msg_end - return_value_begin, incoming_buf.get_data() + return_value_begin); } catch (...) { // avoid memory leaks diff --git a/core/Component.cc b/core/Component.cc index 08cf62634b9347c9aaab8ce8fc8a1655de2e4784..8792c7c5f046b9ec7d421b8425f1e266fe8c9695 100644 --- a/core/Component.cc +++ b/core/Component.cc @@ -28,6 +28,7 @@ #include "Param_Types.hh" #include "Runtime.hh" #include "Optional.hh" +#include "Verdicttype.hh" #include "../common/dbgnew.hh" @@ -93,11 +94,16 @@ void COMPONENT::log() const else TTCN_Logger::log_event_unbound(); } -alt_status COMPONENT::done(Index_Redirect*) const +alt_status COMPONENT::done(VERDICTTYPE* value_redirect, Index_Redirect*) const { if (component_value == UNBOUND_COMPREF) TTCN_error("Performing done " "operation on an unbound component reference."); - return TTCN_Runtime::component_done(component_value); + verdicttype ptc_verdict = NONE; + alt_status status = TTCN_Runtime::component_done(component_value, &ptc_verdict); + if (value_redirect != NULL) { + *value_redirect = ptc_verdict; + } + return status; } alt_status COMPONENT::killed(Index_Redirect*) const diff --git a/core/Component.hh b/core/Component.hh index f4e9853b9857806ad08e4ababc62348194f9e55d..b0f53b536a2cf0d7a20c466a2a13c48ec658b2f1 100644 --- a/core/Component.hh +++ b/core/Component.hh @@ -27,6 +27,7 @@ class Module_Param; template<typename T> class OPTIONAL; +class VERDICTTYPE; // value class for all component types @@ -78,7 +79,7 @@ public: inline boolean is_present() const { return is_bound(); } #endif - alt_status done(Index_Redirect*) const; + alt_status done(VERDICTTYPE* value_redirect, Index_Redirect*) const; alt_status killed(Index_Redirect*) const; boolean running(Index_Redirect*) const; diff --git a/core/Runtime.cc b/core/Runtime.cc index 25d48bc8443c8f062b119d168a56d413293b36bc..71a31ee2d756c4508cf67c6d654417a94b32d828 100644 --- a/core/Runtime.cc +++ b/core/Runtime.cc @@ -105,6 +105,7 @@ int TTCN_Runtime::component_status_table_size = 0; component TTCN_Runtime::component_status_table_offset = FIRST_PTC_COMPREF; struct TTCN_Runtime::component_status_table_struct { alt_status done_status, killed_status; + verdicttype local_verdict; char *return_type; Text_Buf *return_value; } *TTCN_Runtime::component_status_table = NULL; @@ -861,7 +862,8 @@ void TTCN_Runtime::function_finished(const char *function_name) send_function_finished(text_buf); } -alt_status TTCN_Runtime::component_done(component component_reference) +alt_status TTCN_Runtime::component_done(component component_reference, + verdicttype* ptc_verdict /* = NULL */) { if (in_controlpart()) TTCN_error("Done operation cannot be performed " "in the control part."); @@ -880,7 +882,7 @@ alt_status TTCN_Runtime::component_done(component component_reference) case ALL_COMPREF: return all_component_done(); default: - return ptc_done(component_reference); + return ptc_done(component_reference, ptc_verdict); } } @@ -1110,7 +1112,8 @@ void TTCN_Runtime::kill_execution() throw TC_End(); } -alt_status TTCN_Runtime::ptc_done(component component_reference) +alt_status TTCN_Runtime::ptc_done(component component_reference, + verdicttype* ptc_verdict) { if (is_single()) TTCN_error("Done operation on a component reference " "cannot be performed in single mode."); @@ -1151,6 +1154,9 @@ alt_status TTCN_Runtime::ptc_done(component component_reference) success: TTCN_Logger::log_par_ptc(API::ParallelPTC_reason::ptc__done, NULL, NULL, component_reference); + if (ptc_verdict != NULL) { + *ptc_verdict = component_status_table[index].local_verdict; + } return ALT_YES; } @@ -2509,7 +2515,7 @@ void TTCN_Runtime::process_alive(boolean result_value) running_alive_result = result_value; } -void TTCN_Runtime::process_done_ack(boolean done_status, +void TTCN_Runtime::process_done_ack(boolean done_status, verdicttype ptc_verdict, const char *return_type, int return_value_len, const void *return_value) { switch (executor_state) { @@ -2524,7 +2530,7 @@ void TTCN_Runtime::process_done_ack(boolean done_status, TTCN_error("Internal error: Message DONE_ACK arrived in invalid " "state."); } - if (done_status) set_component_done(create_done_killed_compref, + if (done_status) set_component_done(create_done_killed_compref, ptc_verdict, return_type, return_value_len, return_value); create_done_killed_compref = NULL_COMPREF; } @@ -2646,7 +2652,7 @@ void TTCN_Runtime::process_kill_process(component component_reference) } void TTCN_Runtime::set_component_done(component component_reference, - const char *return_type, int return_value_len, + verdicttype ptc_verdict, const char *return_type, int return_value_len, const void *return_value) { switch (component_reference) { @@ -2669,6 +2675,7 @@ void TTCN_Runtime::set_component_done(component component_reference, default: { int index = get_component_status_table_index(component_reference); component_status_table[index].done_status = ALT_YES; + component_status_table[index].local_verdict = ptc_verdict; Free(component_status_table[index].return_type); delete component_status_table[index].return_value; if (return_type != NULL && return_type[0] != '\0') { @@ -2749,6 +2756,7 @@ int TTCN_Runtime::get_component_status_table_index( Malloc(sizeof(*component_status_table)); component_status_table[0].done_status = ALT_UNCHECKED; component_status_table[0].killed_status = ALT_UNCHECKED; + component_status_table[0].local_verdict = NONE; component_status_table[0].return_type = NULL; component_status_table[0].return_value = NULL; component_status_table_size = 1; @@ -2770,6 +2778,7 @@ int TTCN_Runtime::get_component_status_table_index( i <= component_index; i++) { component_status_table[i].done_status = ALT_UNCHECKED; component_status_table[i].killed_status = ALT_UNCHECKED; + component_status_table[i].local_verdict = NONE; component_status_table[i].return_type = NULL; component_status_table[i].return_value = NULL; } @@ -2792,6 +2801,7 @@ int TTCN_Runtime::get_component_status_table_index( for (int i = 0; i < offset_diff; i++) { component_status_table[i].done_status = ALT_UNCHECKED; component_status_table[i].killed_status = ALT_UNCHECKED; + component_status_table[i].local_verdict = NONE; component_status_table[i].return_type = NULL; component_status_table[i].return_value = NULL; } diff --git a/core/Runtime.hh b/core/Runtime.hh index 7f6c9d9cbc25a177553495d21083ba3620761aef..2a90e372c3629f1f1b286e5b53d915465662e668 100644 --- a/core/Runtime.hh +++ b/core/Runtime.hh @@ -212,7 +212,8 @@ public: static void send_function_finished(Text_Buf& text_buf); static void function_finished(const char *function_name); - static alt_status component_done(component component_reference); + static alt_status component_done(component component_reference, + verdicttype* ptc_verdict = NULL); static alt_status component_done(component component_reference, const char *return_type, Text_Buf*& text_buf); static alt_status component_killed(component component_reference); @@ -226,7 +227,8 @@ public: __attribute__ ((__noreturn__)); private: - static alt_status ptc_done(component component_reference); + static alt_status ptc_done(component component_reference, + verdicttype* ptc_verdict); static alt_status any_component_done(); static alt_status all_component_done(); static alt_status ptc_killed(component component_reference); @@ -309,7 +311,7 @@ public: static void process_create_ack(component new_component); static void process_running(boolean result_value); static void process_alive(boolean result_value); - static void process_done_ack(boolean done_status, + static void process_done_ack(boolean done_status, verdicttype ptc_verdict, const char *return_type, int return_value_len, const void *return_value); static void process_killed_ack(boolean killed_status); @@ -318,7 +320,7 @@ public: static void process_kill_process(component component_reference); static void set_component_done(component component_reference, - const char *return_type, int return_value_len, + verdicttype ptc_verdict, const char *return_type, int return_value_len, const void *return_value); static void set_component_killed(component component_reference); static void cancel_component_done(component component_reference); diff --git a/mctr2/mctr/MainController.cc b/mctr2/mctr/MainController.cc index acad299fba793a2c15ca5ce4973b32f270936766..f7149203ca76eb20c4b32264f48c1d303a4f8835 100644 --- a/mctr2/mctr/MainController.cc +++ b/mctr2/mctr/MainController.cc @@ -1573,12 +1573,13 @@ void MainController::component_stopped(component_struct *tc) // the return value was requested send_component_status_mtc(tc->comp_ref, TRUE, FALSE, any_component_done_requested, all_done_result, FALSE, FALSE, - tc->return_type, tc->return_value_len, tc->return_value); + tc->local_verdict, tc->return_type, tc->return_value_len, + tc->return_value); } else { // the return value was not requested send_component_status_mtc(NULL_COMPREF, FALSE, FALSE, any_component_done_requested, all_done_result, FALSE, FALSE, - NULL, 0, NULL); + NONE, NULL, 0, NULL); } if (any_component_done_requested) { any_component_done_requested = FALSE; @@ -1672,12 +1673,12 @@ void MainController::component_terminated(component_struct *tc) if (send_done_to_mtc) { // the return value was requested send_component_status_mtc(tc->comp_ref, TRUE, TRUE, TRUE, - all_done_result, TRUE, all_killed_result, tc->return_type, - tc->return_value_len, tc->return_value); + all_done_result, TRUE, all_killed_result, tc->local_verdict, + tc->return_type, tc->return_value_len, tc->return_value); } else { // the return value was not requested send_component_status_mtc(tc->comp_ref, FALSE, TRUE, TRUE, - all_done_result, TRUE, all_killed_result, NULL, 0, NULL); + all_done_result, TRUE, all_killed_result, NONE, NULL, 0, NULL); } any_component_done_requested = FALSE; any_component_done_sent = TRUE; @@ -3307,11 +3308,13 @@ void MainController::send_alive(component_struct *tc, boolean answer) } void MainController::send_done_ack(component_struct *tc, boolean answer, - const char *return_type, int return_value_len, const void *return_value) + verdicttype local_verdict, const char *return_type, int return_value_len, + const void *return_value) { Text_Buf text_buf; text_buf.push_int(MSG_DONE_ACK); text_buf.push_int(answer ? 1 : 0); + text_buf.push_int(local_verdict); text_buf.push_string(return_type); text_buf.push_raw(return_value_len, return_value); send_message(tc->tc_fd, text_buf); @@ -3498,7 +3501,8 @@ void MainController::send_cancel_done_mtc(component component_reference, void MainController::send_component_status_mtc(component component_reference, boolean is_done, boolean is_killed, boolean is_any_done, boolean is_all_done, boolean is_any_killed, boolean is_all_killed, - const char *return_type, int return_value_len, const void *return_value) + verdicttype local_verdict, const char *return_type, int return_value_len, + const void *return_value) { Text_Buf text_buf; text_buf.push_int(MSG_COMPONENT_STATUS); @@ -3509,6 +3513,7 @@ void MainController::send_component_status_mtc(component component_reference, text_buf.push_int(is_all_done ? 1 : 0); text_buf.push_int(is_any_killed ? 1 : 0); text_buf.push_int(is_all_killed ? 1 : 0); + text_buf.push_int(local_verdict); text_buf.push_string(return_type); text_buf.push_raw(return_value_len, return_value); send_message(mtc->tc_fd, text_buf); @@ -4755,7 +4760,7 @@ void MainController::process_done_req(component_struct *tc) case ANY_COMPREF: if (tc == mtc) { boolean answer = is_any_component_done(); - send_done_ack(mtc, answer, NULL, 0, NULL); + send_done_ack(mtc, answer, NONE, NULL, 0, NULL); if (answer) any_component_done_sent = TRUE; else any_component_done_requested = TRUE; } else send_error_str(tc->tc_fd, "Operation 'any component.done' can " @@ -4764,7 +4769,7 @@ void MainController::process_done_req(component_struct *tc) case ALL_COMPREF: if (tc == mtc) { boolean answer = !is_any_component_running(); - send_done_ack(mtc, answer, NULL, 0, NULL); + send_done_ack(mtc, answer, NONE, NULL, 0, NULL); if (!answer) all_component_done_requested = TRUE; } else send_error_str(tc->tc_fd, "Operation 'all component.done' can " "only be performed on the MTC."); @@ -4787,8 +4792,8 @@ void MainController::process_done_req(component_struct *tc) case TC_EXITING: case TC_EXITED: case PTC_KILLING: - send_done_ack(tc, TRUE, comp->return_type, comp->return_value_len, - comp->return_value); + send_done_ack(tc, TRUE, comp->local_verdict, comp->return_type, + comp->return_value_len, comp->return_value); break; case TC_IDLE: case TC_CREATE: @@ -4803,7 +4808,7 @@ void MainController::process_done_req(component_struct *tc) case PTC_FUNCTION: case PTC_STARTING: case PTC_STOPPING_KILLING: - send_done_ack(tc, FALSE, NULL, 0, NULL); + send_done_ack(tc, FALSE, NONE, NULL, 0, NULL); add_requestor(&comp->done_requestors, tc); break; case PTC_STALE: diff --git a/mctr2/mctr/MainController.h b/mctr2/mctr/MainController.h index abfcb5a8073654d5f6e736fe8707a919bcb7e2d6..eb9e3ce326e1e9bb79775d67c1a6474b955981ca 100644 --- a/mctr2/mctr/MainController.h +++ b/mctr2/mctr/MainController.h @@ -506,7 +506,7 @@ private: static void send_running(component_struct *tc, boolean answer); static void send_alive(component_struct *tc, boolean answer); static void send_done_ack(component_struct *tc, boolean answer, - const char *return_type, int return_value_len, + verdicttype local_verdict, const char *return_type, int return_value_len, const void *return_value); static void send_killed_ack(component_struct *tc, boolean answer); static void send_connect_listen(component_struct *tc, @@ -537,7 +537,7 @@ private: static void send_component_status_mtc(component component_reference, boolean is_done, boolean is_killed, boolean is_any_done, boolean is_all_done, boolean is_any_killed, boolean is_all_killed, - const char *return_type, int return_value_len, + verdicttype local_verdict, const char *return_type, int return_value_len, const void *return_value); static void send_execute_control(const char *module_name); static void send_execute_testcase(const char *module_name, diff --git a/regression_test/Makefile b/regression_test/Makefile index 98d16c3278da1eaf159f8ae3506973cad7acf76f..f8e32a5e76560aa1c193c963047ecb0d093d16f9 100644 --- a/regression_test/Makefile +++ b/regression_test/Makefile @@ -48,7 +48,7 @@ XML ipv6 implicitOmit testcase_defparam transparent HQ16404 cfgFile \ all_from lazyEval tryCatch text2ttcn json ttcn2json profiler templateOmit \ customEncoding makefilegen uidChars checkstate hostid templateIstemplatekind \ selectUnion templateExclusiveRange any_from templatePatternRef indexWithRecofArray \ -connectMapOperTest fuzzy portTranslation ischosen OER functionSubref +connectMapOperTest fuzzy portTranslation ischosen OER functionSubref done ifdef DYN DIRS += loggerplugin junitlogger diff --git a/regression_test/done/.gitignore b/regression_test/done/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..b38bc8a53e9f6882798faf8f4500800989aaa1e1 --- /dev/null +++ b/regression_test/done/.gitignore @@ -0,0 +1,6 @@ +DoneTest +DoneTest.exe +DoneTest*.cc +DoneTest*.hh +compile +DoneTest*.log diff --git a/regression_test/done/DoneTest.ttcn b/regression_test/done/DoneTest.ttcn new file mode 100644 index 0000000000000000000000000000000000000000..c05886688fa2a1f9421f3de261f0deb3c37b740c --- /dev/null +++ b/regression_test/done/DoneTest.ttcn @@ -0,0 +1,138 @@ +/****************************************************************************** + * Copyright (c) 2000-2017 Ericsson Telecom AB + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Botond, Baranyi – initial implementation + * + ******************************************************************************/ + +module DoneTest { + +/***************** Types *****************/ +type record Rec { + integer num, + charstring str +} +with { + extension "done"; +} + +type component CT {} + +/*********** Behavior functions ***********/ +function f_behavior_retval() runs on CT return Rec { + return { num := 10, str := "ab" }; +} + +function f_behavior_none() runs on CT { +} + +function f_behavior_pass() runs on CT { + setverdict(pass); +} + +/*************** Test cases ***************/ + +// Testing 'done' statement on single component with no value redirect +testcase tc_done_single() runs on CT { + var CT comp := CT.create; + comp.start(f_behavior_retval()); + comp.done; + if (comp.running) { + setverdict(fail); + } + setverdict(pass); +} + +// Testing 'done' statement on all components +testcase tc_done_all() runs on CT { + var CT comps[3]; + comps[0] := CT.create; + comps[1] := CT.create; + comps[2] := CT.create; + comps[0].start(f_behavior_retval()); + comps[1].start(f_behavior_none()); + comps[2].start(f_behavior_pass()); + all component.done; + if (comps[0].running or comps[1].running or comps[2].running) { + setverdict(fail); + } + setverdict(pass); +} + +// Testing 'done' statement on any components +testcase tc_done_any() runs on CT { + var CT comps[3]; + comps[0] := CT.create; + comps[1] := CT.create; + comps[2] := CT.create; + comps[0].start(f_behavior_retval()); + comps[1].start(f_behavior_none()); + comps[2].start(f_behavior_pass()); + any component.done; + if (comps[0].running and comps[1].running and comps[2].running) { + setverdict(fail); + } + setverdict(pass); +} + +// Testing 'done' statement on single component with value redirect +// (in this case the value redirect stores the behavior function's return value, +// because there is a matching template in the 'done' statement) +testcase tc_done_retval_redirect() runs on CT { + var CT comp := CT.create; + comp.start(f_behavior_retval()); + var Rec x; + comp.done(Rec: ?) -> value x; + if (comp.running or x != { num := 10, str := "ab" }) { + setverdict(fail); + } + setverdict(pass); +} + +// Testing 'done' statement on single component with value redirect +// (in this case the value redirect stores the local verdict on the component, +// because there is no matching template in the 'done' statement) +testcase tc_done_verdict_redirect() runs on CT { + var CT comp := CT.create; + comp.start(f_behavior_pass()); + var verdicttype x; + comp.done -> value x; + if (comp.running or x != pass) { + setverdict(fail); + } + setverdict(pass); +} + +// Testing 'done' statement on any component from a component array, and with value redirect +// (in this case the value redirect stores the local verdict on the component, +// because there is no matching template in the 'done' statement) +testcase tc_any_from_done_verdict_redirect() runs on CT { + var CT comps[2]; + comps[0] := CT.create; + comps[1] := CT.create; + comps[0].start(f_behavior_retval()); + comps[1].start(f_behavior_none()); + var verdicttype x; + any from comps.done -> value x; // the local verdict on both components is 'none' + if ((comps[0].running and comps[1].running) or x != none) { + setverdict(fail); + } + setverdict(pass); +} + +/************** Control part **************/ +control { + execute(tc_done_single()); + execute(tc_done_all()); + execute(tc_done_any()); + execute(tc_done_retval_redirect()); + execute(tc_done_verdict_redirect()); + execute(tc_any_from_done_verdict_redirect()); +} + +} diff --git a/regression_test/done/Makefile b/regression_test/done/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..352c128930e3912032f11aeb62d9e9eed12b7b9b --- /dev/null +++ b/regression_test/done/Makefile @@ -0,0 +1,56 @@ +############################################################################## +# Copyright (c) 2000-2017 Ericsson Telecom AB +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Eclipse Public License v1.0 +# which accompanies this distribution, and is available at +# http://www.eclipse.org/legal/epl-v10.html +# +# Contributors: +# Baranyi, Botond +# +############################################################################## +TOPDIR := .. +include $(TOPDIR)/Makefile.regression + +.SUFFIXES: .ttcn .hh +.PHONY: all clean dep run + +TTCN3_LIB = ttcn3$(RT2_SUFFIX)-parallel$(DYNAMIC_SUFFIX) + +TTCN3_MODULES = DoneTest.ttcn + +GENERATED_SOURCES = $(TTCN3_MODULES:.ttcn=.cc) +GENERATED_HEADERS = $(GENERATED_SOURCES:.cc=.hh) +ifdef CODE_SPLIT +GENERATED_SOURCES := $(foreach file, $(GENERATED_SOURCES:.cc=), $(addprefix $(file), .cc _seq.cc _set.cc _seqof.cc _setof.cc _union.cc)) +else ifdef SPLIT_TO_SLICES +POSTFIXES := $(foreach file, $(SPLIT_TO_SLICES), $(addsuffix $(file), _part_)) +POSTFIXES := $(foreach file, $(POSTFIXES), $(addprefix $(file), .cc)) +GENERATED_SOURCES2 := $(foreach file, $(GENERATED_SOURCES:.cc=), $(addprefix $(file), $(POSTFIXES))) +GENERATED_SOURCES += $(GENERATED_SOURCES2) +endif + +OBJECTS = $(GENERATED_SOURCES:.cc=.o) + +TARGET = DoneTest$(EXESUFFIX) + +all: $(TARGET) + +$(TARGET): $(GENERATED_SOURCES) $(USER_SOURCES) + $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(LDFLAGS) -o $@ $^ -L$(TTCN3_DIR)/lib -l$(TTCN3_LIB) -L$(OPENSSL_DIR)/lib -lcrypto $($(PLATFORM)_LIBS) + +.ttcn.cc .ttcn.hh: + $(TTCN3_COMPILER) $< + +clean distclean: + -rm -f $(TARGET) $(OBJECTS) $(GENERATED_HEADERS) \ + $(GENERATED_SOURCES) *.log Makefile.bak + +dep: $(GENERATED_SOURCES) + makedepend $(CPPFLAGS) $(GENERATED_SOURCES) + +run: $(TARGET) config.cfg + $(TTCN3_DIR)/bin/ttcn3_start $^ + +.NOTPARALLEL: + diff --git a/regression_test/done/config.cfg b/regression_test/done/config.cfg new file mode 100644 index 0000000000000000000000000000000000000000..3e444cd0615aaf0a4b5f110d596edc5e24d1a7b6 --- /dev/null +++ b/regression_test/done/config.cfg @@ -0,0 +1,19 @@ +############################################################################### +# Copyright (c) 2000-2017 Ericsson Telecom AB +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Eclipse Public License v1.0 +# which accompanies this distribution, and is available at +# http://www.eclipse.org/legal/epl-v10.html +# +# Contributors: +# Baranyi, Botond +# +############################################################################### +[LOGGING] +Logfile := "DoneTest_%r.log" +FileMask := LOG_ALL +ConsoleMask := TTCN_WARNING | TTCN_ERROR | TTCN_TESTCASE | TTCN_STATISTICS + +[EXECUTE] +DoneTest +