/****************************************************************************** * 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: * Magyari, Miklos * * This module tests the basic class syntax * There should be no error markers for this file * * TTCN3 OOP extension v1.3.1 * https://www.etsi.org/deliver/etsi_es/203700_203799/203790/01.03.01_60/es_203790v010301p.pdf) * ******************************************************************************/ module oopPositive language "TTCN-3:2018 Object-Oriented" { type component CT { port PT pt_PT; } type port PT message { inout integer; } with { extension "internal" } /***************************** class tests *****************************/ // minimal classes type class MinimalClass { } type class @abstract MinimalAbstractClass { } type class @final MinimalFinalClass { } type class @trait MinimalTraitClass { } // components type class ClassCT runs on CT mtc CT system CT { } // inheritance type class BaseClass { } type class @abstract AbstractBaseClass { } type class @trait TraitBaseClass { } type class @trait TraitBaseClass2 { } type class SubClass0 extends object { } type class SubClass1 extends BaseClass { const integer m_const := 1; } type class SubClass2 extends BaseClass, TraitBaseClass { const integer m_const := 0; } type class SubClass3 extends BaseClass, TraitBaseClass, TraitBaseClass2 { var integer m_int; } type class SubClass4 extends SubClass1 {} type class @abstract AbstractMethods { // functions without a statement block public function @abstract f_abs(); public function f_get_string() return universal charstring; // implemented function function f_imp(in integer pl_x) return integer { return pl_x; } } type class InheritedAbstractMethods extends AbstractMethods { // inherited abstract function must be implemented public function f_abs() { const integer cl_int := 0; } } // members, methods and constructors type class MembersClass { private var integer m_int_priv := 1; var integer m_int_prot := 2; var integer m_int_pub := 3; public function f_get1() return integer { return m_int_priv; } public function f_times2(in integer pl_times) return integer { return pl_times * m_int_prot; } create (integer pl_p1, integer pl_p2) { m_int_priv := pl_p1; m_int_prot := pl_p2; } } type class ImplicitConstructorClass { var integer m_int1; var charstring m_str1 := "abc"; const float m_float1; const integer m_int2 := 1; // should not be included in the constructor param list var template integer vt_int3; var integer @property m_prop1; var @internal integer @property m_prop2; // should not be included in the constructor param list } type class @trait TraitClass { public function @abstract f_func(in integer pl_in); } type union MyUnion { integer choice1, charstring choice2 } type class VariousMembers { private timer Timer; private const octetstring m_var_octet := 'ABCD'O; var charstring m_var1 := "abc"; private template MyUnion t_union := { choice1 := 12 } template MyUnion t_union2; create (charstring pl_p1, charstring pl_p2) { m_var1 := pl_p2; } } type class @trait AbstractMembersClass { function @abstract f(); function @abstract f2(in integer pl_int); function @abstract f3(in integer pl_int) return charstring; } type class ConstructorOverride { var integer m_int := 0; create (integer pl_int) { m_int := pl_int; } } type class ConstructorOverrideSub { var float m_float; create (float pl_float) : ConstructorOverride(1) { m_float := pl_float; } } type class ConstantInitialization { const integer const_int; create(integer pl_create_int) { const_int := pl_create_int; } } // runs on compatibility type class RunsonClass1 runs on CT { } type class RunsonClass2 extends RunsonClass1 runs on CT { } // mtc compatibility type class MtcClass1 mtc CT { } type class MtcClass2 extends MtcClass1 mtc CT { } // system compatibility type class SystemClass1 system CT { } type class SystemClass2 extends SystemClass1 system CT { } // nested classes type class OuterClass { private var integer m_int := 0; var charstring m_string := "abc"; class NestedClass { private function f_dummy(in integer pl_param) return integer { return 1; } class DeeplyNested { const integer m_const := 0; class EvenDeeper { const charstring m_str := "abc"; class Core { function f_inside(in integer pl_int) return float { return 0.1; } } } } } } // finally block type class @abstract FinallyClass { private const integer m_const := 0; } finally { log(this.m_const); } // `this` reference type class ClassWithThis { var integer vl_a; const float vl_b; public function pl_dummy(in integer pl_int) return integer { return 1; } public function f_dummy2(in charstring pl_dummy) { var integer vl_int := this.pl_dummy(1); } create (integer pl_a, float pl_b) { this.vl_a := pl_a; } } // `super` reference type class SuperBaseClass { private const integer m_const := 1; public function f_get_const() return integer { return m_const; } } // class method identifier reuse in method formal parameters or method body type class ReuseClass { var integer pl_orig := 10; var charstring cl_orig := "abc"; function f_reuse_in_paramlist(in charstring pl_orig) return integer { return 0; } function f_reuse_in_body(integer pl_param) { const float cl_orig := 0.1; } // test method id reuse in a nested StatmentBlock function f_reuse_in_body2(integer pl_param) { { { const float cl_orig := 0.1; } } } } type class SubClass5 extends SuperBaseClass { private const integer m_const2 := 2; private const integer m_const3 := 2; public function f_get_const2() return integer { return m_const2; } public function f_get_all_sum() return integer { var integer vl_sum := 0; const integer cl_const1 := 1; const integer cl_const2 := 2; vl_sum := cl_const1 + cl_const2; return vl_sum; } } type class BaseFunctionClass { public function f_get_one() return integer { return 1; } } type class FuncClass extends BaseFunctionClass { public function f_get_one() return integer { return 2; } private function f_test_super() { // type mismatches var integer vl_int := super.f_get_one(); var integer vl_int2:= f_get_one(); } // class as a function parameter public function f_class_as_param(BaseFunctionClass pl_base) { // function call statement pl_base.f_get_one(); // function call as an rvalue var integer vl_int := pl_base.f_get_one(); } // class as a function parameter (inout) public function f_class_as_inout_param(inout BaseFunctionClass pl_base) { // function call statement pl_base.f_get_one(); // function call as an rvalue var integer vl_int := pl_base.f_get_one(); } } type class CastingClass extends BaseFunctionClass { private function f_priv_getpi(CastingClass pl_class) return float { return 3.1415; } public function f_using_cast(object pl_element) { // of-operator if (element of CastingClass) { // class casting var float vl_pi := f_priv_getpi(pl_element => CastingClass); } } } // private methods can be overridden in subclass type class ClassWithPrivate { private function f_override(in float pl_float) return integer { return 1; } } type class ClassWithPrivateExt extends ClassWithPrivate { public function f_override(charstring pl_chr) return charstring { return pl_chr; } } // class properties type class CorrectWithProperty { private var integer heightVal; // auto property private var integer @property width; // non-auto property var integer @property height { @get => heightVal; @set { if (value > 0) { heightVal := value; } } } // getter-only property private const float piVal := 3.1415; var float @property getPi { @get => piVal; } var float @property getPi2 { @get { return piVal; } } // 'value' manipulation private var integer @property valManip { @get => 10; @set { if (value > 42) { value := -value; heightVal := value; } } } } /*************************** exception handling ****************************/ function f_example() { } type integer MyInteger; type integer MyRange (0 .. 255); // function with multiple catch blocks function f_example2() { f_example(); } catch (MyInteger e) { } catch (MyRange e) { } catch (integer e) { } function f_with_finally() { // function body } finally { // finally block } function f_with_catches_and_finally(in charstring pl_chr) { return; } catch (MyRange e) { } catch (integer e) { } finally { // finally block } // function with a @control modifier function @control f_example3(in integer pl_int) { } // raise exception function f_with_exception(integer pl_int) return integer exception(integer) { if (pl_int > 100) { raise integer:0; } return pl_int * 2; } catch (integer e) { log("Catch block"); } finally { log("Finally block"); } testcase tc_basicSyntax() runs on CT { var object vl_obj := MinimalClass.create; // basic instantiation and constructor calls // constructor call without parameters var MinimalClass vl_minimalClass := MinimalClass.create; // constructor call with empty parameter list var MinimalClass vl_minimalClass2 := MinimalClass.create(); var ClassWithThis vl_thisClass := ClassWithThis.create(12, 13.0); var VariousMembers vl_various := VariousMembers.create("abc", "def"); // class member access var integer vl_intval := vl_thisClass.vl_a; var SubClass5 vl_sub5 := SubClass5.create; vl_intval := vl_sub5.f_get_all_sum(); // class method call vl_sub5.f_get_all_sum(); // class of-operator var OuterClass vl_outerClass := OuterClass.create(0, "0"); if (vl_outerClass of OuterClass) { vl_outerClass.m_string := "xyz"; } // class casting var BaseClass vl_base := BaseClass.create; var object vl_casted := vl_base => SubClass1; var SubClass4 vl_subclass4 := SubClass4.create; var object vl_casted2 := vl_subclass4 => BaseClass; // nested class member reference var float vl_float := vl_outerClass.NestedClass.DeeplyNested.EvenDeeper.Core.f_inside(1); // implicit constructor use var ImplicitConstructorClass vl_impl := ImplicitConstructorClass.create(1, "xyz", 3.14, 2, 5); } control { execute(tc_basicSyntax()); } }