/******************************************************************************
 * Copyright (c) 2000-2021 Ericsson Telecom AB
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v2.0
 * which accompanies this distribution, and is available at
 * https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.html
 *
 * Contributors:
 *   Balasko, Jeno
 *   Baranyi, Botond
 *
 ******************************************************************************/

// This module contains tests for using subreferences (field names and array indexes) on 
// parameterized templates.
module TpardTemplateSubref {

import from TfunctionSubref all;

/* * * * Parameterized templates * * * */
template Rec t_pard_rec(in template integer p_num, in template charstring p_str) := 
  { num := p_num, str := p_str };

template RoI t_pard_roi(in integer p_init, in integer p_mul) :=
  { p_init, p_init * p_mul, p_init * p_mul * p_mul };

template Uni t_pard_uni(in template octetstring p_val) :=
  { os := p_val };

template Arr t_pard_arr(in template Arr p_val) :=
  { p_val[3], p_val[2], p_val[1], p_val[0] };

template Complex t_pard_complex(in template Rec p_rec, in template RoI p_roi) :=
  { rec := p_rec, roi := p_roi, unis := { { os := t_os }, { i := c_init } } };

/* * * * Constants and templates * * * */
template integer t_int := 10;
template charstring t_cs := ? length(1..4);
const integer c_init := 6;
const integer c_mul := 2;
template octetstring t_os := ('00'O, '11'O, '22'O, '33'O);

/* * * * Helper function * * * */
function f_test_pard_temp(in template charstring p1, in template integer p2,
  in template octetstring p3, in template octetstring p4)
{
  if (log2str(p1) == log2str(t_cs)) { setverdict(pass); }
  else { setverdict(fail, "Expected: ", t_cs, ", got: ", p1); }
  if (log2str(p2) == log2str(c_init)) { setverdict(pass); }
  else { setverdict(fail, "Expected: ", c_init, ", got: ", p2); }
  if (log2str(p3) == log2str(t_os)) { setverdict(pass); }
  else { setverdict(fail, "Expected: ", t_os, ", got: ", p3); }
  if (log2str(p4) == log2str(t_arr[1])) { setverdict(pass); }
  else { setverdict(fail, "Expected: ", t_arr[1], ", got: ", p4); }
}

/* * * * Test cases * * * */
testcase tc_pard_temp_var_assign() runs on CT
{
  var template charstring vt1 := t_pard_rec(t_int, t_cs).str;
  var template integer vt2 := t_pard_roi(c_init, c_mul)[0];
  var template octetstring vt3 := t_pard_uni(t_os).os;
  var template octetstring vt4 := t_pard_arr(t_arr)[3];
  if (log2str(vt1) == log2str(t_cs)) { setverdict(pass); }
  else { setverdict(fail, "Expected: ", t_cs, ", got: ", vt1); }
  if (log2str(vt2) == log2str(c_init)) { setverdict(pass); }
  else { setverdict(fail, "Expected: ", c_init, ", got: ", vt2); }
  if (log2str(vt3) == log2str(t_os)) { setverdict(pass); }
  else { setverdict(fail, "Expected: ", t_os, ", got: ", vt3); }
  if (log2str(vt4) == log2str(t_arr[0])) { setverdict(pass); }
  else { setverdict(fail, "Expected: ", t_arr[0], ", got: ", vt4); }
}

testcase tc_pard_temp_match() runs on CT
{
  var charstring v_good1 := "rT.8";
  var integer v_good2 := 12;
  var octetstring v_good3 := '22'O;
  var octetstring v_good4 := '12EF'O;
  var integer v_bad1 := 331;
  var integer v_bad2 := 7;
  var octetstring v_bad3 := '44'O;
  var octetstring v_bad4 := 'ABCDEF'O;
  if (match(v_good1, t_pard_rec(t_int, t_cs).str)) { setverdict(pass); }
  else { setverdict(fail, "Expected ", v_good1, " to match ", t_pard_rec(t_int, t_cs).str); }
  if (match(v_good2, t_pard_roi(c_init, c_mul)[1])) { setverdict(pass); }
  else { setverdict(fail, "Expected ", v_good2, " to match ", t_pard_roi(c_init, c_mul)[1]); }
  if (match(v_good3, t_pard_uni(t_os).os)) { setverdict(pass); }
  else { setverdict(fail, "Expected ", v_good3, " to match ", t_pard_uni(t_os).os); }
  if (match(v_good4, t_pard_arr(t_arr)[3])) { setverdict(pass); }
  else { setverdict(fail, "Expected ", v_good4, " to match ", t_pard_arr(t_arr)[3]); }
  if (not match(v_bad1, t_pard_rec(t_int, t_cs).num)) { setverdict(pass); }
  else { setverdict(fail, "Expected ", v_bad1, " not to match ", t_pard_rec(t_int, t_cs).num); }
  if (not match(v_bad2, t_pard_roi(c_init, c_mul)[2])) { setverdict(pass); }
  else { setverdict(fail, "Expected ", v_bad2, " not to match ", t_pard_roi(c_init, c_mul)[2]); }
  if (not match(v_bad3, t_pard_uni(t_os).os)) { setverdict(pass); }
  else { setverdict(fail, "Expected ", v_bad3, " not to match ", t_pard_uni(t_os).os); }
  if (not match(v_bad4, t_pard_arr(t_arr)[1])) { setverdict(pass); }
  else { setverdict(fail, "Expected ", v_bad4, " not to match ", t_pard_arr(t_arr)[1]); }
}

testcase tc_pard_temp_value() runs on CT
{
  if (isvalue(t_pard_rec(t_int, t_cs).num)) { setverdict(pass); }
  else { setverdict(fail, "Expected ", t_pard_rec(t_int, t_cs).num, " to be a value."); }
  if (isvalue(t_pard_roi(c_init, c_mul)[1])) { setverdict(pass); }
  else { setverdict(fail, "Expected ", t_pard_roi(c_init, c_mul)[1], " to be a value."); }
  if (not isvalue(t_pard_uni(t_os).os)) { setverdict(pass); }
  else { setverdict(fail, "Expected ", t_pard_uni(t_os).os, " to not be a value."); }
  if (isvalue(t_pard_arr(t_arr)[0])) { setverdict(pass); }
  else { setverdict(fail, "Expected ", t_pard_arr(t_arr)[0], " to be a value."); }
  if (valueof(t_pard_rec(t_int, t_cs).num) == valueof(t_int)) { setverdict(pass); }
  else { setverdict(fail, "Expected: ", t_int, ", got: ", t_pard_rec(t_int, t_cs).num); }
  if (valueof(t_pard_roi(c_init, c_mul)[0]) == c_init) { setverdict(pass); }
  else { setverdict(fail, "Expected: ", c_init, ", got: ", t_pard_roi(c_init, c_mul)[0]); }
  if (valueof(t_pard_arr(t_arr)[1]) == valueof(t_arr[2])) { setverdict(pass); }
  else { setverdict(fail, "Expected: ", t_arr[2], ", got: ", t_pard_arr(t_arr)[1]); }
}

testcase tc_pard_temp_structure() runs on CT
{
  var template Rec rec1 := { num := t_pard_rec(t_int, t_cs).num, str := t_pard_rec(t_int, t_cs).str };
  var template Rec rec1_e := { num := t_int, str := t_cs };
  var template Rec rec2 := { t_pard_roi(c_init, c_mul)[1], "abc" };
  var template Rec rec2_e := { c_init * c_mul, "abc" };
  var template RoI roi := { t_pard_roi(c_init, c_mul)[2], (0..infinity) };
  var template RoI roi_e := { c_init * c_mul * c_mul, (0..infinity) };
  var template Uni uni := { os := t_pard_uni(t_os).os };
  var template Uni uni_e := { os := t_os };
  var template Arr arr := { [0] := t_pard_arr(t_arr)[3], [1] := t_pard_arr(t_arr)[2],
    [2] := t_pard_arr(t_arr)[1], [3] := t_pard_arr(t_arr)[0] }; // == t_arr
  if (log2str(rec1) == log2str(rec1_e)) { setverdict(pass); }
  else { setverdict(fail, "Expected: ", rec1_e, ", got: ", rec1); }
  if (log2str(rec2) == log2str(rec2_e)) { setverdict(pass); }
  else { setverdict(fail, "Expected: ", rec2_e, ", got: ", rec2); }
  if (log2str(roi) == log2str(roi_e)) { setverdict(pass); }
  else { setverdict(fail, "Expected: ", roi_e, ", got: ", roi); }
  if (log2str(uni) == log2str(uni_e)) { setverdict(pass); }
  else { setverdict(fail, "Expected: ", uni_e, ", got: ", uni); }
  if (log2str(arr) == log2str(t_arr)) { setverdict(pass); }
  else { setverdict(fail, "Expected: ", t_arr, ", got: ", arr); }
}

testcase tc_pard_temp_parameter() runs on CT
{
  f_test_pard_temp(t_pard_rec(t_int, t_cs).str, t_pard_roi(c_init, c_mul)[0],
    t_pard_uni(t_os).os, t_pard_arr(t_arr)[2]);
}

testcase tc_pard_temp_send_receive() runs on CT
{
  connect(mtc:pt, mtc:pt);
  pt.send(t_pard_rec(t_int, t_cs).num);
  pt.send(t_pard_roi(c_init, c_mul)[1]);
  pt.send('11'O);
  pt.send(t_pard_arr(t_arr)[0]);
  var default def := activate(as_ct());
  var integer bad_int;
  var octetstring bad_os;
  t.start(1.0);
  alt {
    [] pt.receive(t_pard_rec(t_int, t_cs).num) { setverdict(pass); }
    [] pt.receive(integer:?) -> value bad_int 
      { setverdict(fail, "Expected: ", t_pard_rec(t_int, t_cs).num, ", got: ", bad_int); }
  }
  alt {
    [] pt.receive(t_pard_roi(c_init, c_mul)[1]) { setverdict(pass); }
    [] pt.receive(integer:?) -> value bad_int 
      { setverdict(fail, "Expected: ", t_pard_roi(c_init, c_mul)[1], ", got: ", bad_int); }
  }
  alt {
    [] pt.receive(t_pard_uni(t_os).os) { setverdict(pass); }
    [] pt.receive(octetstring:?) -> value bad_os 
      { setverdict(fail, "Expected: ", t_pard_uni(t_os).os, ", got: ", bad_os); }
  }
  alt {
    [] pt.receive(t_pard_arr(t_arr)[0]) { setverdict(pass); }
    [] pt.receive(octetstring:?) -> value bad_os 
      { setverdict(fail, "Expected: ", t_pard_arr(t_arr)[0], ", got: ", bad_os); }
  }
  deactivate(def);
}

testcase tc_pard_temp_complex() runs on CT
{
  var template Rec rec := { t_int, t_cs };
  var template RoI roi := { 1, 2, 3 };
  var template RoI roi_res := { t_pard_complex(rec, roi).rec.num, t_pard_complex(rec, roi).roi[2],
    t_pard_complex(rec, roi).unis[1].i };
  var template RoI roi_res_e := { rec.num, roi[2], c_init };
  if (log2str(roi_res) == log2str(roi_res_e)) { setverdict(pass); }
  else { setverdict(fail, "Expected: ", roi_res_e, ", got: ", roi_res); }
  if (match('00'O, t_pard_complex(rec, {}).unis[0].os)) { setverdict(pass); }
  else { setverdict(fail, "Expected '00'O to match ", t_pard_complex(rec, {}).unis[0].os); }
  if (isvalue(t_pard_complex(t_pard_rec(t_int, t_cs), t_pard_roi(c_init, c_mul)).roi[2])) { setverdict(pass); }
  else { setverdict(fail, "Expected ", t_pard_complex(t_pard_rec(t_int, t_cs), t_pard_roi(c_init, c_mul)).roi[2], " to be a value"); }
}

/* * * * Control part * * * */
control {
  execute(tc_pard_temp_var_assign());
  execute(tc_pard_temp_match());
  execute(tc_pard_temp_value());
  execute(tc_pard_temp_structure());
  execute(tc_pard_temp_parameter());
  execute(tc_pard_temp_send_receive());
  execute(tc_pard_temp_complex());
}

}
