/****************************************************************************** * Copyright (c) 2000-2016 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: * Balasko, Jeno * Baranyi, Botond * Kovacs, Ferenc * Raduly, Csaba * ******************************************************************************/ module io { import from IOAsn all; type component O {} //The following TTCN code is not accepted (from HN81328) type record MyRecord1 { integer a, boolean b optional // , float f } type set MySet1 { integer a, boolean b optional // , float f } type record MyRecord2 { MyRecord1 m } type set MySet2 { MySet1 m } template MyRecord1 MyTemplate1ln := { ? } with {optional "implicit omit"} // b is set to omit, ERROR BY TITAN //The compiler complains that there are too few elements in the list (one instead of two). // Common::Location::error is called from from Ttcn::Template::set_templatetype // in case TEMPLATE_LIST //The following (using assignment notation) is accepted: template MyRecord1 MyTemplate1an := { a := ? } with {optional "implicit omit"} // b is set to omit template MySet1 MySetTemplate1an := { a := ? } with {optional "implicit omit"} // b is set to omit function check1(in template MyRecord1 r1, in boolean a_init1, in boolean b_init1, out charstring reason1) return boolean { var charstring t_str := log2str(r1); // looks like: { a := ?, b := } if (not a_init1 and not b_init1) { return t_str == ""; } else { var charstring rx := "{ a := (*), b := (*) }"; var charstring grp := regexp(t_str, rx, 0); log("grp for a :", grp); if (grp != "?") { // a is always expected to be '?' reason1 := " a should be "; if (a_init1) { reason1 := reason1 & "initialised" } else { reason1 := reason1 & "uninitialised" } // never gets here return false; } grp := regexp(t_str, rx, 1); log("grp for b :", grp); reason1 := " b should be " if (b_init1) { if (grp != "omit") { reason1 := reason1 & "initialised" return false; } } else { if (grp != "") { reason1 := reason1 & "uninitialised" return false; } } return true; } } function check1s(in template MySet1 r5, in boolean a_init5, in boolean b_init5, out charstring reason5) return boolean { var charstring t_str := log2str(r5); // looks like: { a := ?, b := } if (not a_init5 and not b_init5) { return t_str == ""; } else { var charstring rx := "{ a := (*), b := (*) }"; var charstring grp := regexp(t_str, rx, 0); log("grp for a :", grp); if (grp != "?") { // a is always expected to be '?' reason5 := " a should be "; if (a_init5) { reason5 := reason5 & "initialised" } else { reason5 := reason5 & "uninitialised" } // never gets here return false; } grp := regexp(t_str, rx, 1); log("grp for b :", grp); reason5 := " b should be " if (b_init5) { if (grp != "omit") { reason5 := reason5 & "initialised" return false; } } else { if (grp != "") { reason5 := reason5 & "uninitialised" return false; } } return true; } } function check2(in template MyRecord2 r2, in boolean a_init2, in boolean b_init2, out charstring reason2) return boolean { if (a_init2 or b_init2) { return check1(r2.m, a_init2, b_init2, reason2); } else { return log2str(r2) == ""; } } function check2s(in template MySet2 r2s, in boolean a_init2s, in boolean b_init2s, out charstring reason2s) return boolean { if (a_init2s or b_init2s) { return check1s(r2s.m, a_init2s, b_init2s, reason2s); } else { return log2str(r2s) == ""; } } /***************************** from 27.7 of the TTCN3 standard 4.1.1 *****************************/ // reference templates with explicitly set fields template MyRecord1 MyTemplate1 := { a := ?, b := omit } template MyRecord2 MyTemplate2 := { m := { a := ?, b := omit }} template MySet1 MySetTemplate1 := { a := ?, b := omit } template MySet2 MySetTemplate2 := { m := { a := ?, b := omit }} testcase tc12() runs on O { var charstring reason; if (check1(MyTemplate1, true, true, reason)) { setverdict(pass); } else { setverdict(fail, reason); } if (check1s(MySetTemplate1, true, true, reason)) { setverdict(pass); } else { setverdict(fail, reason); } if (check2(MyTemplate2, true, true, reason)) { setverdict(pass); } else { setverdict(fail, reason); } if (check2s(MySetTemplate2, true, true, reason)) { setverdict(pass); } else { setverdict(fail, reason); } } // reference templates template MyRecord1 MyTemplate1a := { a := ? } // b is undefined template MyRecord1 MyTemplate1b := { a := ? } with {optional "explicit omit"} // b is undefined template MySet1 MySetTemplate1a := { a := ? } // b is undefined template MySet1 MySetTemplate1b := { a := ? } with {optional "explicit omit"} // b is undefined testcase tc1ab() runs on O { var charstring reason; if (check1(MyTemplate1a, true, false, reason)) { setverdict(pass); } else { setverdict(fail, reason); } if (check1s(MySetTemplate1a, true, false, reason)) { setverdict(pass); } else { setverdict(fail, reason); } if (check1(MyTemplate1b, true, false, reason)) { setverdict(pass); } else { setverdict(fail, reason); } if (check1s(MySetTemplate1b, true, false, reason)) { setverdict(pass); } else { setverdict(fail, reason); } } template MyRecord2 MyTemplate2a := {} // m and its subfields are undefined, ERROR BY TITAN template MyRecord2 MyTemplate2b := { m := { a := ?}}; // m.b is undefined template MySet2 MySetTemplate2b := { m := { a := ?}}; // m.b is undefined testcase tc2ab() runs on O { var charstring reason; if (check2(MyTemplate2a, false, false, reason)) { setverdict(pass); } else { setverdict(fail, reason); } if (check2(MyTemplate2b, true, false, reason)) { setverdict(pass); } else { setverdict(fail, reason); } if (check2s(MySetTemplate2b, true, false, reason)) { setverdict(pass); } else { setverdict(fail, reason); } } // templates with attribute template MyRecord1 MyTemplate11 := { a := ? } with {optional "implicit omit"} // same as MyTemplate1, b is set to omit template MySet1 MySetTemplate11 := { a := ? } with {optional "implicit omit"} template MyRecord2 MyTemplate21 := { m := { a := ?}} with {optional "implicit omit"} // same as MyTemplate2, by recursive application of the attribute template MySet2 MySetTemplate21 := { m := { a := ?}} with {optional "implicit omit"} testcase tc_11() runs on O { var charstring reason; if (check1(MyTemplate11, true, true, reason)) { setverdict(pass); } else { setverdict(fail, reason, MyTemplate11); } if (check1s(MySetTemplate11, true, true, reason)) { setverdict(pass); } else { setverdict(fail, reason, MyTemplate11); } } testcase tc_21() runs on O { var charstring reason; if (check2(MyTemplate21, true, true, reason)) { setverdict(pass); } else { setverdict(fail, reason, MyTemplate21); } if (check2s(MySetTemplate21, true, true, reason)) { setverdict(pass); } else { setverdict(fail, reason, MyTemplate21); } } template MyRecord2 MyTemplate22 := { m := MyTemplate1a } with {optional "implicit omit"} // same as MyTemplate2, { m := { a := ?, b := omit }}, by recursive application of the attribute // MyTemplate1a has b undefined template MySet2 MySetTemplate22 := { m := MySetTemplate1a } with {optional "implicit omit"} testcase tc_22() runs on O { var charstring reason; if (check2(MyTemplate22, true, false, reason)) { setverdict(pass); } // According to the standard, this ^^^^^ should be true, but Titan does not implement recursive implicit omit else { setverdict(fail, MyTemplate22, reason); } if (check2s(MySetTemplate22, true, false, reason)) { setverdict(pass); } // According to the standard, this ^^^^^ should be true, but Titan does not implement recursive implicit omit else { setverdict(fail, MyTemplate22, reason); } } template MyRecord2 MyTemplate23 := {} with {optional "implicit omit"} // ERROR BY TITAN // same as MyTemplate2a, m remains undefined testcase tc_23() runs on O { var charstring reason; if (check2(MyTemplate23, false, false, reason)) { setverdict(pass); } else { setverdict(fail, MyTemplate23, reason); } } template MyRecord2 MyTemplate24 := { m := MyTemplate1b } with {optional "implicit omit"} // same as MyTemplate2b, the attribute on the lower scope is not overwritten template MySet2 MySetTemplate24 := { m := MySetTemplate1b } with {optional "implicit omit"} testcase tc_24() runs on O { var charstring reason; if (check2(MyTemplate22, true, false, reason)) { setverdict(pass); } else { setverdict(fail, MyTemplate24, reason); } if (check2s(MySetTemplate22, true, false, reason)) { setverdict(pass); } else { setverdict(fail, MyTemplate24, reason); } } template MyRecord2 MyTemplate25 := { m := MyTemplate1b } with {optional override "implicit omit"} // same as MyTemplate2, the attribute on the lower scope is overwritten // MyTemplate1b has b undefined and (redundant) explicit omit testcase tc_25() runs on O { var charstring reason; if (check2(MyTemplate25, true, false, reason)) { setverdict(pass); } // According to the standard, this ^^^^^ should be true, but Titan does not implement recursive implicit omit else { setverdict(fail, MyTemplate25, reason); } } /***************************** from 6.2 ***************************/ type record R62 { integer f1, integer f2 optional, integer f3, integer f4 optional, integer f5 optional } template R62 x1 := { 1, -, 2 } with {optional "implicit omit"} template R62 x2 := { 1, 2 } with {optional "implicit omit"} template R62 x3 := { 1, 2, 3 } with {optional "implicit omit"} // "const" gives the same old error: // Too few elements in value list notation for type `@io.R62' testcase tc62() runs on O { var charstring logged; logged := log2str(x1); if (match(logged, "{ f1 := 1, f2 := omit, f3 := 2, f4 := omit, f5 := omit }")) { setverdict(pass); } else { setverdict(fail, logged); } logged := log2str(x2); if (match(logged, "{ f1 := 1, f2 := 2, f3 := , f4 := omit, f5 := omit }")) { setverdict(pass); } else { setverdict(fail, logged); } logged := log2str(x3); if (match(logged, "{ f1 := 1, f2 := 2, f3 := 3, f4 := omit, f5 := omit }")) { setverdict(pass); } else { setverdict(fail, logged); } } //testcase passer() runs on O { setverdict(pass); } /////////////////////// // MODULE PARAMETERS // /////////////////////// type myrec1 myarr[2] type record myrec1 { integer i optional, charstring c } type set myset1 { integer i optional, charstring c } type record myrec2 { integer i optional, myrec1 mr1 optional, myrec1 mr2 } type set myset2 { integer i optional, myset1 ms1 optional, myset1 ms2 } type union myuni { integer i, myrec1 mr1, myrec2 mr2 } type record of myrec1 myrecof1 type set of myrec1 mysetof1 type record of myrec2 myrecof2 type set of myset2 mysetof2 modulepar myarr marr with { optional "implicit omit" } modulepar myrec1 mrec1 with { optional "implicit omit" } modulepar myset1 mset1 with { optional "implicit omit" } modulepar myrec2 mrec2 with { optional "implicit omit" } modulepar myset2 mset2 with { optional "implicit omit" } modulepar myuni muni with { optional "implicit omit" } modulepar myrecof1 mrecof1 with { optional "implicit omit" } modulepar mysetof1 msetof1 with { optional "implicit omit" } modulepar myrecof2 mrecof2 with { optional "implicit omit" } modulepar mysetof2 msetof2 /*:= { [0] := { ms2 := { c := "clinton" } } }*/ with { optional "implicit omit" } testcase tc_iompar_recset() runs on O { // For empty records: // B: { i := , c := } // A: { i := omit, c := } var myrec1 brec1 := { c := "clementin" } var myrec1 arec1 := { i := omit, c := "clementin" } if (log2str(mrec1) == log2str(arec1)) { setverdict(pass) } else { setverdict(fail) } // Empty sets are not allowed. var myset1 bset1 := { c := "cup" } var myset1 aset1 := { i := omit, c := "cup" } if (log2str(mset1) == log2str(aset1)) { setverdict(pass) } else { setverdict(fail) } // B: { i := , mr1 := , mr2 := { i := , c := "cello" } } // A: { i := omit, mr1 := omit, mr2 := { i := omit, c := "cello" } } var myrec2 brec2 := { mr2 := { c := "cello" } } var myrec2 arec2 := { omit, omit, { i := omit, c := "cello" } } if (log2str(mrec2) == log2str(arec2)) { setverdict(pass) } else { setverdict(fail) } // B: { i := , ms1 := , ms2 := { i := , c := "cello" } } // A: { i := omit, ms1 := omit, ms2 := { i := omit, c := "cello" } } var myset2 bset2 := { ms2 := { c := "cello" } } var myset2 aset2 := { i := omit, ms1 := omit, ms2 := { i := omit, c := "cello" } } if (log2str(mset2) == log2str(aset2)) { setverdict(pass) } else { setverdict(fail) } } testcase tc_iompar_uni() runs on O { // B: { mr2 := { i := , mr1 := , mr2 := { i := , c := "cuba" } } } // A: { mr2 := { i := omit, mr1 := omit, mr2 := { i := omit, c := "cuba" } } } var myuni buni := { mr2 := { mr2 := { c := "cuba" } } } var myuni auni := { mr2 := { i := omit, mr1 := omit, mr2 := { i := omit, c := "cuba" } } } if (log2str(muni) == log2str(auni)) { setverdict(pass) } else { setverdict(fail) } } testcase tc_iompar_listarr() runs on O { // B: { { i := , c := }, { i := , c := "clementin" } } // A: { { i := , c := }, { i := omit, c := "clementin" } } var myarr barr := { [1] := { c := "clementin" } } var myarr aarr := { [1] := { i := omit, c := "clementin" } } if (log2str(marr) == log2str(aarr)) { setverdict(pass) } else { setverdict(fail) } // B: { { i := , c := }, { i := , c := "clinton" } } // A: { { i := , c := }, { i := omit, c := "clinton" } } // Unbound values will not be checked at all. var myrecof1 brecof1 := { [1] := { c := "clinton" } } var myrecof1 arecof1 := { [1] := { i := omit, c := "clinton" } } if (log2str(mrecof1) == log2str(arecof1)) { setverdict(pass) } else { setverdict(fail) } // B: { { i := , c := }, { i := , c := "clinton" } } // A: { { i := , c := }, { i := omit, c := "clinton" } } var mysetof1 bsetof1 := { [1] := { c := "clinton" } } var mysetof1 asetof1 := { [1] := { i := omit, c := "clinton" } } if (log2str(msetof1) == log2str(asetof1)) { setverdict(pass) } else { setverdict(fail) } // B: { { i := , mr1 := , mr2 := { i := , c := } }, { i := , mr1 := , mr2 := { i := , c := "clinton" } } } // A: { { i := , mr1 := , mr2 := { i := , c := } }, { i := omit, mr1 := omit, mr2 := { i := omit, c := "clinton" } } } var myrecof2 brecof2 := { [1] := { mr2 := { c := "clinton" } } } var myrecof2 arecof2 := { [1] := { i := omit, mr1 := omit, mr2 := { i := omit, c := "clinton" } } } if (log2str(mrecof2) == log2str(arecof2)) { setverdict(pass) } else { setverdict(fail) } // B: { { i := , ms1 := , ms2 := { i := , c := } }, { i := , ms1 := , ms2 := { i := , c := "clinton" } } } // A: { { i := , ms1 := , ms2 := { i := , c := } }, { i := omit, ms1 := omit, ms2 := { i := omit, c := "clinton" } } } var mysetof2 bsetof2 := { [1] := { ms2 := { c := "clinton" } } } var mysetof2 asetof2 := { [1] := { i := omit, ms1 := omit, ms2 := { i := omit, c := "clinton" } } } if (log2str(msetof2) == log2str(asetof2)) { setverdict(pass) } else { setverdict(fail) } } type record MyRecord { integer field1 optional, integer field2 optional, MySubRecord subRecord optional } type record MySubRecord { integer subField1 optional, integer subField2 optional } template MyRecord t_MyRecord1(integer v_int1, integer v_int2, MySubRecord v_subRecord) := { field1 := v_int1, field2 := v_int2, subRecord := v_subRecord } template MyRecord t_MyRecord2(integer v_int1, integer v_int2, MySubRecord v_subRecord) modifies t_MyRecord1 := { subRecord := v_subRecord } // without { optional "implicit omit" } template MyRecord t_MyRecord2_io(integer v_int1, integer v_int2, MySubRecord v_subRecord) modifies t_MyRecord1 := { subRecord := v_subRecord } with { optional "implicit omit" } template MyRecord t_MyRecord2_io2(integer v_int1, integer v_int2, MySubRecord v_subRecord) modifies t_MyRecord1 := { field1 := v_int1, field2 := v_int2, subRecord := v_subRecord } with { optional "implicit omit" } template MySubRecord t_MySubRecord(integer v_int1, integer v_int2) := { subField1 := v_int1, subField2 := v_int2 } with { optional "implicit omit" } // HP93133: "Implicit omit overwrites attributes of modified template" testcase tc_HP93133() runs on O { var MySubRecord subRecord := valueof(t_MySubRecord(1, 2)) // 1,2 var MyRecord record1 := valueof(t_MyRecord1(5, 6, subRecord)) // 5,6,1,2 // modifies without implicit omit: var MyRecord record2 := valueof(t_MyRecord2(7, 8, subRecord)) // 7,8,1,2 if (record2 == { 7, 8, { 1, 2 } }) { setverdict(pass) } else { setverdict(fail) } // modifies, with implicit omit: var MyRecord record3 := valueof(t_MyRecord2_io(7, 8, subRecord)); // 7,8,1,2 if (record3 == { 7, 8, { 1, 2 } }) { setverdict(pass) } else { setverdict(fail) } // parent is not modified anymore... var MyRecord record4 := valueof(t_MyRecord2_io2(0, 0, subRecord)); // 0,0,1,2 if (record4 == { 0, 0, { 1, 2 } }) { setverdict(pass) } else { setverdict(fail) } // ...unless it's requested } // HQ30261: "Implicit omit doesn't work for modulepar default values" type record MyOwnRecord { integer f1, integer f2 optional } modulepar MyOwnRecord tsp_MyOwnRecord_init := { f1 := 1 } with { optional "implicit omit" } modulepar MyOwnRecord tsp_MyOwnRecord_empty with { optional "implicit omit" } testcase tc_HQ30261() runs on O { if (match(tsp_MyOwnRecord_init, { 1, omit })) { setverdict(pass) } else { setverdict(fail) } if (not isbound(tsp_MyOwnRecord_empty.f1) and tsp_MyOwnRecord_empty.f2 == omit) { setverdict(pass) } else { setverdict(fail) } } // Implicit omit for fields of records embedded in a union type union Something { Outer outer, Inner inner, octetstring os } type record Outer { integer i, Inner inner optional } type record Inner { float f, charstring cs optional } const Something c_something_value := { outer := { i := 10, inner := { f := 7.1 } } } with { optional "implicit omit" } template Something t_something_target := { outer := { i := 10, inner := { f := 7.1, cs := omit } } } testcase tc_io_embedded() runs on O { if (match(c_something_value, t_something_target)) { setverdict(pass); } else { setverdict(fail, c_something_value); } } // Implicit omit specified with the not used symbol (-) with the value list notation type record of Outer RoO; const RoO c_notused_value := { { 3, - }, { 4, { 3.9, - } } } with { optional "implicit omit" } template RoO t_notused_target := { { 3, omit }, { 4, { 3.9, omit } } } with { optional "implicit omit" } testcase tc_io_notused() runs on O { if (match(c_notused_value, t_notused_target)) { setverdict(pass); } else { setverdict(fail, c_notused_value); } } // Implicit omit on an ASN.1 record, with only empty brackets (which is considered as value list notation) template AsnSequence t_asn_rec_empty := { } with { optional "implicit omit" }; template AsnSequence t_asn_rec_empty_exp := { omit, omit, omit, omit }; testcase tc_io_asn_record_empty() runs on O { if (log2str(t_asn_rec_empty) == log2str(t_asn_rec_empty_exp)) { setverdict(pass); } else { setverdict(fail, t_asn_rec_empty); } } control { execute(tc12()); execute(tc1ab()); execute(tc2ab()); execute(tc_11()); execute(tc_21()); execute(tc_22()); execute(tc_23()); execute(tc_24()); execute(tc_25()); execute(tc62()); log("MyTemplate1ln = ",MyTemplate1ln); log("MyTemplate1an = ",MyTemplate1an); log("MyTemplate1 = ",MyTemplate1); log("MyTemplate2 = ",MyTemplate2); log("MyTemplate1a = ",MyTemplate1a); log("MyTemplate1b = ",MyTemplate1b); log("MyTemplate2a = ",MyTemplate2a); log("MyTemplate2b = ",MyTemplate2b); log("MyTemplate11 = ",MyTemplate11); log("MyTemplate21 = ",MyTemplate21); log("MyTemplate22 = ",MyTemplate22); log("MyTemplate23 = ",MyTemplate23); log("MyTemplate24 = ",MyTemplate24); log("MyTemplate25 = ",MyTemplate25); log("x1=", x1); log("x2=", x2); log("x3=", x3); execute(tc_iompar_recset()) execute(tc_iompar_uni()) execute(tc_iompar_listarr()) execute(tc_HP93133()) execute(tc_HQ30261()) execute(tc_io_embedded()); execute(tc_io_notused()); execute(tc_io_asn_record_empty()); } with { optional "implicit omit" } }