1 /******************************************************************************
2 * Copyright (c) 2000-2014 Ericsson Telecom AB
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License v1.0
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/epl-v10.html
7 ******************************************************************************/
8 module dual { // straight off 4.21.8 of reference guide
10 // PDU types to be sent and received on the ports
11 type record ControlRequest {
15 type record ControlResponse{
19 type record ErrorSignal {
23 type record PDUType1 {
26 with { variant "/* dummy */" }
28 type record PDUType2 {
31 with { variant (text) "FIELDLENGTH(8)" }
33 type record of charstring strings
34 with { variant "/* dummy */" }
36 type record of octetstring blob
37 with { variant "/* dummy */" }
40 // the encoder/decoder functions are written in C++
41 external function enc_PDUType1(in PDUType1 par) return octetstring
42 // there was a typo here ------------^ (was lowercase t)
43 with { extension "prototype(convert)" }
45 // Same as above, but generated by the compiler
46 external function enc_PDUType1_gen(in PDUType1 par) return octetstring
47 with { extension "prototype(convert) encode(RAW)" }
50 // another conversion function in C++
51 external function dec_PDUType1(in octetstring stream,
52 out PDUType1 result) return integer
53 with { extension "prototype(backtrack)" }
55 // Again, generated by the compiler
56 external function dec_PDUType1_gen(in octetstring stream,
57 out PDUType1 result) return integer
58 with { extension "prototype(backtrack) decode(RAW)" }
60 // And now, something completely different! Sliding decoding!
62 // Hand-written decoder function
63 external function dec_slider(inout octetstring stream, out PDUType1 result) return integer
64 with { extension "prototype(sliding)" }
67 external function dec_slider_gen(inout octetstring stream, out PDUType1 result) return integer
68 with { extension "prototype(sliding) decode(RAW) errorbehavior(INCOMPL_MSG:IGNORE, LEN_ERR:IGNORE)" }
71 external function dec_slider_gen2(inout octetstring stream, out PDUType2 result) return integer
72 with { extension "prototype(sliding) decode(RAW) errorbehavior(INCOMPL_MSG:IGNORE, LEN_ERR:IGNORE)" }
74 // Various other prototypes
75 external function dec_blob_fast(in octetstring stream, out blob val)
76 with { extension "prototype(fast) decode(RAW)" }
78 external function dec_strings(in octetstring stream) return strings
79 with { extension "prototype(convert) decode(RAW)" }
81 external function bk_strings(in octetstring stream, out strings s) return integer
82 with { extension "prototype(backtrack) decode(RAW)" }
84 external function slide_strings(inout octetstring strm, out strings val) return integer
85 with { extension "prototype(sliding) decode(RAW)" }
87 function bogus(in octetstring i, out ControlRequest o) return integer
89 // Yes, you can do this.
90 // If you can decode a ControlRequest in TTCN-3 code, go right ahead.
91 // It's more likely to be useful when mapping from one user-defined type
92 // to another (e.g. shuffling fields from one record to another).
93 // Implementing RAW decoding is going to be a bit more tricky...
94 o := { oct2char(i) }; // living dangerously...
97 with { extension "prototype(backtrack)" }
100 /************************************ The ports ************************************/
102 // port type PT1 is the external interface of the dual-faced port
103 // with its own Test Port. See section "The purpose of Test Ports" in the API guide.
104 type port PT1 message {
110 } with { extension "provider" }
112 // port type PT2 is the internal interface of the dual-faced port
113 // This port is communicating (in)directly with the SUT using the Test Port of PT1.
114 type port PT2 message {
117 // out ErrorSignal; // this is bogus
118 inout PDUType1, PDUType2;
122 } with { extension "user PT1
123 out(ControlRequest -> ControlRequest: simple; /* no conversion */
124 PDUType1 -> octetstring: function(enc_PDUType1); /* call function */
125 PDUType2 -> octetstring: encode(RAW)) /* call built-in codec */
127 /* Multi-target out mapping ???? */
128 out(octetstring -> octetstring : decode(RAW),
129 ControlRequest : function(bogus),
132 in(ControlResponse -> ControlResponse : simple; /* no conversion */
133 ErrorSignal -> - : discard; /* drop */
134 octetstring -> PDUType1: function(dec_PDUType1), /* call function */
135 PDUType2: decode(RAW), /* built-in decoder */
139 // As above, but uses the generated converter functions
140 type port PT2GEN message {
143 // out ErrorSignal; // this is bogus
144 inout PDUType1, PDUType2;
147 } with { extension "user PT1
148 out(ControlRequest -> ControlRequest: simple; /* no conversion */
149 PDUType1 -> octetstring: function(enc_PDUType1_gen); /* call function */
150 PDUType2 -> octetstring: encode(RAW); /* call built-in codec */
151 octetstring -> PDUType1: function(dec_slider_gen) /* outgoing map with a prototype(sliding) decode(...) !! */
154 in(ControlResponse -> ControlResponse : simple; /* no conversion */
155 ErrorSignal -> - : discard; /* drop */
156 octetstring -> PDUType2: function(dec_slider_gen2) /* call function; prototype(sliding) */
157 , PDUType1: decode(RAW) /* built-in decoder */
158 , strings : function(slide_strings)
160 /*, strings : function(bk_strings) /* call function; protoype(backtrack)
161 /* , strings : function(dec_strings) /* call function; protoype(convert) */
162 /* , blob : function(dec_blob_fast) /* call function; protoype(fast) */
163 /* prototype(backtrack) cannot be used when prototype(sliding) is present,
164 although code gen for sliding is not supported */
165 /*, - : discard cannot be used when proto sliding is present */)"
168 type port STRINGPORT message
174 in(octetstring -> strings : function(dec_strings) /* call function; protoype(convert) */
175 ; ControlResponse -> - : discard
176 ; ErrorSignal -> - : discard )"
179 type port FASTPORT message
185 in(octetstring -> blob : function(dec_blob_fast) /* call function; protoype(fast) */
186 ; ControlResponse -> - : discard
187 ; ErrorSignal -> - : discard )"
193 type component MTC_CT {
194 // port PT2 MTC_PORT;
195 port PT2GEN MTC_PORT;
198 type component SYSTEM_SCT {
199 port PT1 SYSTEM_PORT;
200 //port PT1 ANOTHER_SYSTEM_PORT;
203 testcase tc_DUALFACED_func () runs on MTC_CT system SYSTEM_SCT
205 map(mtc:MTC_PORT, system:SYSTEM_PORT);
206 //map(mtc:MTC_PORT, system:ANOTHER_SYSTEM_PORT);
207 // a second (different) mapping completely prevents sending of messages on the port
209 // Send in twice the FIELDLENGTH of PDUType2. This should be decoded
210 // as *two* consecutive incoming messages.
211 MTC_PORT.send(PDUType1 : {"type: 1!type: 2!"});
212 /** MTC_PORT is a PT2GEN, a "user" port. It uses the PT1 "provider" port.
213 * It has no user-conrollable parts; no skeleton is generated.
214 * Sending a PDUType1 calls enc_PDUType1_gen to transform it into octetstring
215 * which is the sent through PT1_PROVIDER::otgoing_send.
216 * PT1 is the provder; it is a "real" port with a skeleton.
218 * PT1_PROVIDER::otgoing_send is written to call PT2GEN::incoming_message
219 * (because it's a fake port; a real one would call incoming_message
220 * from an event handler). PT2GEN is derived from PT1_PROVIDER.
221 * Here the incoming mapping happens.
226 [] MTC_PORT.receive(PDUType2 : {"type: 1!"}) { setverdict(pass, "got PDU2"); }
227 [] MTC_PORT.receive /* anything else */{ setverdict(fail, "got unknown response"); }
228 [] t.timeout { setverdict(fail, "time-out"); }
233 [] MTC_PORT.receive(PDUType2 : {"type: 2!"}) { setverdict(pass, "got PDU2"); }
234 [] MTC_PORT.receive /* anything else */{ setverdict(fail, "got unknown response"); }
235 [] t.timeout { setverdict(fail, "time-out"); }
237 unmap(mtc:MTC_PORT, system:SYSTEM_PORT);
240 testcase tc_DUALFACED_simple () runs on MTC_CT system SYSTEM_SCT
242 map(mtc:MTC_PORT, system:SYSTEM_PORT);
244 MTC_PORT.send(ControlRequest:{ "CReq from simple" });
247 // When the port gets a ControlRequest which begins with 'C', it sends back a ControlResponse
249 [] MTC_PORT.receive(ControlResponse:?) { setverdict(pass /* , "got response" */); }
250 [] MTC_PORT.receive /* anything else */{ setverdict(fail, "got unknown response"); }
251 [] t.timeout { setverdict(fail, "time-out"); }
256 MTC_PORT.send(ControlRequest:{ "Another CReq from simple" });
258 // Because the text in the ControlRequest does not start with a 'C',
259 // the port sends back an ErrorSignal... which is discarded by the incoming mapping.
261 [] MTC_PORT.receive(ControlResponse:?) { setverdict(fail, "got WRONG response"); }
262 [] MTC_PORT.receive /* anything else */{ setverdict(fail, "got unknown response"); }
263 [else] /* nothing received */ { setverdict(pass); }
266 unmap(mtc:MTC_PORT, system:SYSTEM_PORT);
269 testcase tc_DUALFACED_slid() runs on MTC_CT system SYSTEM_SCT
271 map(mtc:MTC_PORT, system:SYSTEM_PORT);
272 var PDUType1 p1 := { "Ulysses!" };
273 var PDUType2 p2 := { p1.text };
274 var octetstring output := enc_PDUType1(p1);
275 MTC_PORT.send(output);
280 [] MTC_PORT.receive(PDUType2 : p2) { setverdict(pass); }
281 [] MTC_PORT.receive /* anything else */ { setverdict(fail, "got unknown response"); }
282 [] t.timeout { setverdict(fail, "time-out at ", __LINE__); }
286 /*** test that sending a message in two parts gets reassembled ***/
287 var integer len := lengthof(output);
288 var integer half_len := len / 2;
289 // Send the first half \\
290 var octetstring first_half := substr(output, 0, half_len);
291 MTC_PORT.send(first_half);
294 [] MTC_PORT.receive /* anything */ {
295 setverdict(fail, "It wasn't supposed to receive anything yet");
297 [else] /* nothing received */ { setverdict(pass); }
301 // Send the second half \\
302 var octetstring second_half := substr(output, half_len, len - half_len);
303 MTC_PORT.send(second_half);
306 [] MTC_PORT.receive(PDUType2 : p2) { setverdict(pass); }
307 [] MTC_PORT.receive /* anything else */ { setverdict(fail, "got unknown response"); }
308 [] t.timeout { setverdict(fail, "time-out at ", __LINE__); }
311 unmap(mtc:MTC_PORT, system:SYSTEM_PORT);
315 execute( tc_DUALFACED_simple() );
316 execute( tc_DUALFACED_func() );
317 execute( tc_DUALFACED_slid() );