oop.ttcn 20.3 KB
Newer Older
1
/******************************************************************************
Adam Knapp's avatar
Adam Knapp committed
2
 * Copyright (c) 2000-2021 Ericsson Telecom AB
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
 * 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:
 *   Baranyi, Botond
 *
 ******************************************************************************/
module oop {

type component CT {
  port PT pt;
}

type port PT message { inout integer; } with { extension "internal" }

20 21
type record of integer IntList;

22 23 24 25
///////////////////////////////////////////////////
///////////////////// CLASSES /////////////////////
///////////////////////////////////////////////////

26 27 28 29 30
type record Rec {
  charstring str,
  IntList list
}

31 32 33 34 35
type union Uni {
  integer i,
  charstring cs
}

36 37 38 39
function f_this_as_param(object p) {
  log(p);
}

40
type class BaseClass runs on CT mtc CT system CT {
41
  /*protected*/ const integer m_const := 1;
42
  private const IntList m_const2 := { 1, 2, 3 };
43 44
  /*protected*/ var charstring m_var;
  private template octetstring m_temp := ? length (1..4);
45
  /*protected*/ var template float m_var_temp;
46 47 48 49 50 51
  //private PT m_port; // port members not supported
  /*protected*/ timer m_timer;
  private timer m_timer_array[3];
  
  //public template integer m_temp_pard(integer p) := p; // parameterized template members not supported
  
52
  // this would also be the implicit constructor's header:
53 54
  create(integer p_const, IntList p_const2, charstring p_var,
         template octetstring p_temp, template float p_var_temp) {
55 56 57
    m_const := p_const;
    m_const := 2;
    m_var := p_var;
58
    m_const2[2] := p_const2[0];
59 60 61
    m_temp := p_temp;
    m_temp := *;
    m_var_temp := p_var_temp;
62 63
    //m_port := p_port;
    //m_timer := p_timer;
64 65 66 67 68 69 70
  }
  
  public function f(in integer x) return integer {
    m_var := m_var & int2str(x);
    return x;
  }
  
71 72 73 74 75 76 77 78
  public function f2(in integer x) return Rec {
    var Rec ret_val := { str := int2str(x), list := {} };
    for (var integer i := 0; i < x; i := i + 1) {
      ret_val.list[i] := i;
    }
    return ret_val;
  }
  
79 80 81
  public function get_var() return charstring {
    return m_var;
  }
82
  
83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130
  public function get_var_temp() return template float {
    return m_var_temp;
  }
  
  public function members_and_methods_test() {
    var BaseClass v_base := BaseClass.create(4, { 1, 2, 4 }, "a", 'FF'O, (0.0 .. 10.0));
    var IntList il := { 1, 2, 4 };
    var template float tf := (0.0 .. 10.0);
    var BaseClass v_sub := SubClass.create(4, il, "a", 'FF'O, tf);
    var BaseClass v_final := FinalClass.create(4, il, "a", 'FF'O, tf, 8, "x", -1.5, *);
    
    log(v_base.f(6));
    log(v_sub.f(6));
    log(v_final.f(6));
    
    log(v_base.m_const);
    log(v_sub.m_var_temp);
    log(v_final.get_var());
    log(v_final.f2(3).list[1]);
    
    if (v_base.f(6) != 6) {
      setverdict(fail, "v_base.f(6) = ", v_base.f(6));
    }
    if (v_sub.f(6) != 5) {
      setverdict(fail, "v_sub.f(6) = ", v_sub.f(6));
    }
    if (v_final.f(6) != 14) {
      setverdict(fail, "v_final.f(6) = ", v_final.f(6));
    }
    
    if (log2str(v_base.f(6)) != "6") {
      setverdict(fail, "log2str(v_base.f(6)) = ", log2str(v_base.f(6)));
    }
    
    if (v_base.m_const != 2) {
      setverdict(fail, "v_base.m_const = ", v_base.m_const);
    }
    if (log2str(v_sub.m_var_temp) != "(0.000000 .. 10.000000)") {
      setverdict(fail, "v_sub.m_var_temp = ", v_sub.m_var_temp);
    }
    if (v_final.get_var() != "ax66") {
      setverdict(fail, "v_final.get_var() = ", v_final.get_var());
    }
    if (v_final.f2(3).list[1] != 1) {
      setverdict(fail, "v_final.f2(3).list[1] = ", v_final.f2(3).list[1]);
    }
  }
  
131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150
  public function this_test(in integer get_var, in charstring p_log_str) {
    var integer m_const := 9;
    if (this.m_const != 2) {
      setverdict(fail, "this.m_const = ", this.m_const);
    }
    if (this.get_var() != m_var) {
      setverdict(fail, "this.get_var() = ", this.get_var(), ", m_var = ", m_var);
    }
    if (log2str(this) != p_log_str) {
      setverdict(fail, "this = ", this, ", expected: ", p_log_str);
    }
    var BaseClass v_ref := this;
    if (not v_ref == this) {
      setverdict(fail, "equality failed");
    }
    var BaseClass v_ref2;
    v_ref2 := this;
    if (this != v_ref2) {
      setverdict(fail, "inequality failed");
    }
151
    f_this_as_param(this);
152
  }
153 154 155 156
}
finally {
  //pt.send(-1);
  log(m_var);
157 158 159 160
  log(this);
  log(this);
  log(this);
  log(this);
161 162
}

163 164 165 166 167 168
type class SubClass extends BaseClass {  
  create(integer p_const := 1, IntList p_const2, charstring p_var,
         template octetstring p_temp, template float p_var_temp)
         : BaseClass(p_const, p_const2, p_var, p_temp, p_var_temp) {
    m_const3 := 'FFFF'O;
    m_var := m_var & "x";
169 170
  }
  
171 172
  const octetstring m_const3 := 'AB'O; // the parser currently doesn't accept constants without initial value
  
173
  public function f(in integer x) return integer {
174
    return super.f(x) - 1;
175 176 177 178
  }
}

type class @final FinalClass extends SubClass {
179 180
  private const integer m_final_const := 1;
  private template charstring m_final_temp := ? length (1..4);
181 182
  private var float m_final_var := 1.0;
  private var template octetstring m_final_var_temp := ''O;
183
  
184
  public function @final f(in integer x) return integer {
185 186 187 188 189 190 191 192 193
    return super.f(x) + m_final_const + 1;
  }
  
  public function get_uni() return Uni {
    return { i := m_final_const };
  }
  
  public function get_uni_temp() return template Uni {
    return { cs := m_final_temp };
194 195 196 197 198 199 200 201 202 203 204 205
  }
}


type class @abstract AbstractClass {
  public function @abstract f_abs(inout integer x) return boolean;
  public function f_con(in charstring x) {
    log(x);
  }
}

type class ConcreteClass extends AbstractClass {
206
  create(octetstring p_const := 'AB'O) {
207
    // for compilation only, to make sure there are no name clashes between parameter default values
208 209
    log(p_const);
  }
210 211 212 213 214 215
  public function f_abs(inout integer x) return boolean {
    x := x + 1;
    return x > 0;
  }
}

216

217 218 219 220 221 222 223 224 225 226 227
type external class ExternalClass {
  public external function f_ext(in integer x) return charstring;
}

type class InternalClass extends ExternalClass {
  public function f_int() return integer {
    return 0;
  }
  public external function f_ext2();
}

228 229
testcase tc_members_and_methods() runs on CT {
  var BaseClass v_base := BaseClass.create(4, { 1, 2, 4 }, "a", 'FF'O, (0.0 .. 10.0));
230
  v_base.members_and_methods_test();
231 232 233
  setverdict(pass);
}

234 235 236 237 238 239 240 241 242 243 244
testcase tc_logging() runs on CT {
  var BaseClass v_base := BaseClass.create(4, { 1, 2, 4 }, "a", 'FF'O, (0.0 .. 10.0));
  var IntList il := { 1, 2, 4 };
  var template float tf := (0.0 .. 10.0);
  var BaseClass v_sub := SubClass.create(4, il, "a", 'FF'O, tf);
  var BaseClass v_final := FinalClass.create(4, il, "a", 'FF'O, tf, 8, "x", -1.5, *);

  log(v_base);
  log(v_sub);
  log(v_final);
  
245 246 247
  var charstring v_base_str := "BaseClass";
  var charstring v_sub_str := "SubClass ( BaseClass )";
  var charstring v_final_str := "FinalClass ( SubClass ( BaseClass ) )";
248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285
  
  if (log2str(v_base) != v_base_str) {
    setverdict(fail, "v_base: ", v_base);
  }
  if (log2str(v_sub) != v_sub_str) {
    setverdict(fail, "v_sub: ", v_sub);
  }
  if (log2str(v_final) != v_final_str) {
    setverdict(fail, "v_final: ", v_final);
  }
  setverdict(pass);
}

testcase tc_equality() runs on CT {
  var BaseClass v_base := BaseClass.create(4, { 1, 2, 4 }, "a", 'FF'O, (0.0 .. 10.0));
  var BaseClass v_base2 := BaseClass.create(4, { 1, 2, 4 }, "a", 'FF'O, (0.0 .. 10.0));
  if (v_base == v_base2) {
    setverdict(fail, "Equality of different objects failed");
  }
  if (not v_base != v_base2) {
    setverdict(fail, "Inquality of different objects failed");
  }
  
  var BaseClass v_ref := v_base;
  if (not v_ref == v_base) {
    setverdict(fail, "Equality of object and reference to object failed");
  }
  if (v_ref != v_base) {
    setverdict(fail, "Inequality of object and reference to object failed");
  }
  
  var BaseClass v_ref2 := v_ref;
  if (not v_ref2 == v_base) {
    setverdict(fail, "Equality of object and indirect reference to object failed");
  }
  if (v_ref2 != v_base) {
    setverdict(fail, "Inequality of object and indirect reference to object failed");
  }
286 287 288 289 290 291 292 293 294
  
  var SubClass v_sub := SubClass.create(4, { 1, 2, 4 }, "a", 'FF'O, (0.0 .. 10.0));
  var BaseClass v_ref3 := v_sub;
  if (not v_ref3 == v_sub) {
    setverdict(fail, "Equality of subclass object and superclass reference failed");
  }
  if (v_ref3 != v_sub) {
    setverdict(fail, "Inquality of subclass object and superclass reference failed");
  }
295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344
  setverdict(pass);
}

testcase tc_null() runs on CT {
  var BaseClass v_base := BaseClass.create(4, { 1, 2, 4 }, "a", 'FF'O, (0.0 .. 10.0));
  var IntList il := { 1, 2, 4 };
  var template float tf := (0.0 .. 10.0);
  var SubClass v_sub := SubClass.create(4, il, "a", 'FF'O, tf);
  var FinalClass v_final := FinalClass.create(4, il, "a", 'FF'O, tf, 8, "x", -1.5, *);
  
  var BaseClass v_null := null;
  var BaseClass v_empty;
  
  log(v_null);
  log(v_empty);
  
  if (v_base == v_null) {
    setverdict(fail, "BaseClass equality with null reference failed");
  }
  if (v_base == v_empty) {
    setverdict(fail, "BaseClass equality with empty reference failed");
  }
  if (v_null != v_empty) {
    setverdict(fail, "null reference equality with empty reference failed");
  }
  if (v_base == null) {
    setverdict(fail, "BaseClass equality with null value failed");
  }
  if (null == v_final) {
    setverdict(fail, "FinalClass equality with null value failed");
  }
  if (v_null != null) {
    setverdict(fail, "null reference equality with null value failed");
  }
  if (null != v_empty) {
    setverdict(fail, "null value equality with empty reference failed");
  }
  setverdict(pass);
}

testcase tc_this() runs on CT {
  var BaseClass v_base := BaseClass.create(4, { 1, 2, 4 }, "a", 'FF'O, (0.0 .. 10.0));
  v_base.this_test(10, log2str(v_base));
  setverdict(pass);
}

testcase tc_references() runs on CT {
  var BaseClass v_base := BaseClass.create(4, { 1, 2, 4 }, "a", 'FF'O, 1.0);
  var SubClass v_sub := SubClass.create(4, { 1, 2, 4 }, "a", 'FF'O, 1.0);
  var FinalClass v_final := FinalClass.create(4, { 1, 2, 4 }, "a", 'FF'O, 1.0, 8, "x", -1.5, *);
345
  var BaseClass v_null := null;
346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365
  
  var BaseClass v_ref1;
  if (v_ref1 != null) {
    setverdict(fail, "#1");
  }
  v_ref1 := v_base;
  if (v_ref1 != v_base) {
    setverdict(fail, "#2");
  }
  var integer v_int := v_final.f(1);
  if (v_int != 9) {
    setverdict(fail, "#3, ", v_final.f(1));
  }
  v_int := v_final.f(2);
  if (v_int != 10) {
    setverdict(fail, "#4, ", v_final.f(2));
  }
  if (not isbound(v_final.f2(3).list[1])) {
    setverdict(fail, "#5");
  }
366
  if (not isvalue(v_base.get_var_temp())) {
367 368
    setverdict(fail, "#6");
  }
369
  if (not ispresent(v_base.get_var_temp())) {
370 371 372 373 374 375 376 377
    setverdict(fail, "#7");
  }
  if (ischosen(v_final.get_uni().cs)) {
    setverdict(fail, "#8");
  }
  if (not ischosen(v_final.get_uni_temp().cs)) {
    setverdict(fail, "#9");
  }
378 379
  if (v_final.f2(3).list[1] + v_final.f(-6) != v_base.f(3) * float2int(valueof(v_sub.get_var_temp()))) {
    setverdict(fail, "#10, ", v_final.f2(3).list[1] + v_final.f(-6), " != ", v_base.f(3) * float2int(valueof(v_sub.get_var_temp())));
380 381 382 383
  }
  if (match(v_final.get_uni(), v_final.get_uni_temp())) {
    setverdict(fail, "#11, ", match(v_final.get_uni(), v_final.get_uni_temp()));
  }
384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401
  if (not isbound(v_sub)) {
    setverdict(fail, "#12");
  }
  if (isbound(v_null)) {
    setverdict(fail, "#13");
  }
  if (not isvalue(v_final)) {
    setverdict(fail, "#14");
  }
  if (isvalue(v_null)) {
    setverdict(fail, "#15");
  }
  if (not ispresent(v_base)) {
    setverdict(fail, "#16");
  }
  if (ispresent(v_null)) {
    setverdict(fail, "#17");
  }
402 403 404 405
  var BaseClass v_base2 := v_null;
  if (v_base2 != null) {
    setverdict(fail, "#18");
  }
406 407 408
  setverdict(pass);
}

409

410
type class Node {
411 412 413
  var integer data;
  var Node next;
  public function get_next() return Node { return next; }
414
  public function f() return integer { return 1; }
415 416 417 418 419 420 421 422 423 424 425 426 427
}

function f_test(in Node p1, inout Node p2, out Node p3,
                in charstring p1_str, in charstring p2_str) return Node {
  if (log2str(p1) != p1_str) {
    setverdict(fail, "Invalid 'in' parameter value at start: ", p1, ", expected: ", p1_str);
  }
  if (log2str(p2) != p2_str) {
    setverdict(fail, "Invalid 'inout' parameter value at start: ", p2, ", expected: ", p2_str);
  }
  if (p3 != null) {
    setverdict(fail, "Invalid 'out' parameter value at start: ", p3, ", expected: null");
  }
428 429 430 431
  var integer i := p1.f();
  if (i != 1) {
    setverdict(fail, "Invalid value returned by function call of 'in' parameter: ", i);
  }
432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457
  var Node tmp := p2;
  p3 := p1;
  p1 := null;
  p2 := null;
  return tmp;
}

testcase tc_function_pars_and_retval() runs on CT {
  var Node x := Node.create(1, Node.create(2, Node.create(3, null)));
  var Node y := Node.create(0, null);
  var Node z := Node.create(-1, null);
  var charstring x_str := log2str(x);
  var charstring y_str := log2str(y);
  var Node res := f_test(x, y, z, x_str, y_str);
  if (log2str(x) != x_str) {
    setverdict(fail, "Invalid 'in' parameter value at end: ", x, ", expected: ", x_str);
  }
  if (y != null) {
    setverdict(fail, "Invalid 'inout' parameter value at end: ", y, ", expected: null");
  }
  if (log2str(z) != x_str) {
    setverdict(fail, "Invalid 'out' parameter value at end: ", z, ", expected: ", x_str);
  }
  if (log2str(res) != y_str) {
    setverdict(fail, "Invalid return value: ", res, ", expected: ", y_str);
  }
458
  
459 460 461 462
  setverdict(pass);
}

type class Node2 {
463 464 465
  var object data;
  var Node2 next;
  public function get_data() return object { return data; }
466
  public function get_next() return Node2 { return next; }
467 468 469
  public function f(in object p) { data := p; }
}

470
function f_test_in(Node p1, Node2 p2) {
471
  p2.f(p1.get_next());
472 473
}

474 475 476 477 478 479
type class InParTester {
  public function test(object x) return boolean {
    return x of Node;
  }
}

480 481 482 483
testcase tc_function_pars_in() runs on CT {
  var Node n1 := Node.create(1, Node.create(2, null));
  var Node2 n2 := Node2.create(null, null);
  f_test_in(n1, n2);
484 485
  if (log2str(n2.get_data()) != log2str(n1.get_next())) {
    setverdict(fail, "Expected: ", n1.get_next(), ", got: ", n2.get_data());
486
  }
487 488 489
  var InParTester t := InParTester.create;
  if (not t.test(n1.get_next())) {
    setverdict(fail, "InParTester failed");
490
  }
491
  setverdict(pass);
492
}
493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523

type class Something {
  public function toString() return universal charstring {
    return "Something";
  }
}

testcase tc_object() runs on CT {
  var object v_obj := Node.create(3, null);
  var Node v_node := Node.create(3, null);
  if (log2str(v_obj) != log2str(v_node)) {
    setverdict(fail, "v_obj: ", v_obj, ", v_node: ", v_node);
  }
  if (v_obj.toString() != "Object") {
    setverdict(fail, "v_obj.toString(): ", v_obj.toString());
  }
  if (v_obj.toString() != v_node.toString()) {
    setverdict(fail, "v_obj.toString(): ", v_obj.toString(), ", v_node.toString(): ", v_node.toString());
  }
  var object v_obj2 := Something.create;
  var Something v_smthn := Something.create;
  if (v_obj2.toString() != "Something") {
    setverdict(fail, "v_obj2.toString(): ", v_obj2.toString());
  }
  if (v_obj2.toString() != v_smthn.toString()) {
    setverdict(fail, "v_obj2.toString(): ", v_obj2.toString(), ", v_smthn.toString(): ", v_smthn.toString());
  }
  if (v_obj2.toString()[3] != "e") {
    setverdict(fail, "v_obj2.toString()[3]: ", v_obj2.toString()[3]);
  }
  var Node2 v_node2 := Node2.create(Something.create, Node2.create(Node.create(1, null), null));
524
  if (log2str(v_node2.get_data()) != "Something" or log2str(v_node2.get_next().get_data()) != "Node") {
525 526 527 528 529
    setverdict(fail, "v_node2: ", v_node2);
  }
  setverdict(pass);
}

530 531 532 533 534 535 536 537 538 539 540
testcase tc_abstract() runs on CT {
  var AbstractClass v := ConcreteClass.create;
  var integer x := 0;
  if (v.f_abs(x) and x == 1) {
    setverdict(pass);
  }
  else {
    setverdict(fail);
  }
}

541 542 543 544 545 546 547 548 549
type class Destructor { }
finally {
  setverdict(pass);
}

testcase tc_destructor() runs on CT {
  var Destructor x := Destructor.create;
}

550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661
testcase tc_of_operator() runs on CT {
  var SubClass v_sub := SubClass.create(4, { 1, 2, 4 }, "a", 'FF'O, 1.0);
  var SubClass v_final := FinalClass.create(4, { 1, 2, 4 }, "a", 'FF'O, 1.0, 8, "x", -1.5, *);
  var object v_obj := Node.create(3, null);
  var BaseClass v_null := null;
  
  if (not v_sub of BaseClass) {
    setverdict(fail, "#1");
  }
  if (not v_sub of SubClass) {
    setverdict(fail, "#2");
  }
  if (v_sub of FinalClass) {
    setverdict(fail, "#3");
  }
  if (not v_final of BaseClass) {
    setverdict(fail, "#4");
  }
  if (not v_final of SubClass) {
    setverdict(fail, "#5");
  }
  if (not v_final of FinalClass) {
    setverdict(fail, "#6");
  }
  if (v_sub of Node) {
    setverdict(fail, "#7");
  }
  if (not v_sub of object) {
    setverdict(fail, "#8");
  }
  if (not v_obj of object) {
    setverdict(fail, "#9");
  }
  if (not v_obj of Node) {
    setverdict(fail, "#10");
  }
  if (v_obj of AbstractClass) {
    setverdict(fail, "#11");
  }
  if (v_null of BaseClass) {
    setverdict(fail, "#12");
  }
  if (v_null of object) {
    setverdict(fail, "#13");
  }
  setverdict(pass);
}

testcase tc_select_class() runs on CT {
  var SubClass v_sub := SubClass.create(4, { 1, 2, 4 }, "a", 'FF'O, 1.0);
  var SubClass v_final := FinalClass.create(4, { 1, 2, 4 }, "a", 'FF'O, 1.0, 8, "x", -1.5, *);
  var object v_obj := Node.create(3, null);
  var BaseClass v_null := null;
  
  select class (v_sub) {
    case (FinalClass) {
      setverdict(fail, "#1 FinalClass");
    }
    case (SubClass) {
      setverdict(pass);
    }
    case (BaseClass) {
      setverdict(fail, "#1 BaseClass");
    }
  }
  
  select class (v_final) {
    case (FinalClass) {
      setverdict(pass);
    }
    case (SubClass) {
      setverdict(fail, "#2 SubClass");
    }
    case (BaseClass) {
      setverdict(fail, "#2 BaseClass");
    }
  }
  
  select class (v_obj) {
    case (object) {
      setverdict(pass);
    }
    case (Node) {
      setverdict(fail, "#3 Node");
    }
    case else {
      setverdict(fail, "#3 else");
    }
  }
  
  select class (v_null) {
    case (BaseClass) {
      setverdict(fail, "#4 BaseClass");
    }
    case (Node) {
      setverdict(fail, "#4 Node");
    }
    case (object) {
      setverdict(fail, "#4 object");
    }
    case else {
      setverdict(pass);
    }
  }
}

testcase tc_casting() runs on CT {
  var SubClass v_sub := SubClass.create(4, { 1, 2, 4 }, "a", 'FF'O, 1.0);
  var SubClass v_final := FinalClass.create(4, { 1, 2, 4 }, "a", 'FF'O, 1.0, 8, "x", -1.5, *);
  var object v_obj := Node.create(3, null);
  var BaseClass v_null := null;
  var Node v_null2 := null;
662
  var object v_con := ConcreteClass.create;
663 664
  
  var BaseClass v_base := v_sub => BaseClass;
665
  if (log2str(v_base) != log2str(v_sub)) {
666 667 668 669 670 671 672 673 674 675 676 677 678 679
    setverdict(fail, "#1: ", v_base);
  }
  var FinalClass v_final2 := v_final => FinalClass;
  if (log2str(v_final2) != log2str(v_final)) {
    setverdict(fail, "#2: ", v_final2);
  }
  var Node v_node := v_obj => (v_null2);
  if (log2str(v_node) != log2str(v_obj)) {
    setverdict(fail, "#3: ", v_node);
  }
  var SubClass v_sub2 := v_sub => SubClass;
  if (log2str(v_sub2) != log2str(v_sub)) {
    setverdict(fail, "#4: ", v_sub2);
  }
680 681 682 683 684 685 686 687
  var object v_obj2 := v_sub => object;
  if (log2str(v_obj2) != log2str(v_sub)) {
    setverdict(fail, "#5: ", v_obj2);
  }
  var AbstractClass v_abs := v_con => AbstractClass;
  if (log2str(v_abs) != log2str(v_con)) {
    setverdict(fail, "#6: ", v_abs);
  }
688 689
  @try {
    var SubClass v_bad := v_null => SubClass;
690
    setverdict(fail, "#7: Error expected");
691 692 693
  }
  @catch(msg) {
    if (not match(msg, pattern "*Casting a null reference")) {
694
      setverdict(fail, "#7: Invalid error: ", msg);
695 696 697 698
    }
  }
  @try {
    var FinalClass v_bad2 := v_sub => FinalClass;
699
    setverdict(fail, "#8: Error expected");
700 701 702
  }
  @catch(msg) {
    if (not match(msg, pattern "*Invalid casting to class type `FinalClass'")) {
703
      setverdict(fail, "#8: Invalid error: ", msg);
704 705
    }
  }
706 707 708 709
  /*var integer v_int := (v_obj => Node).data;
  if (v_int != 3) {
    setverdict(fail, "#9: ", v_int);
  }*/
710 711 712
  setverdict(pass);
}

713

714
control {
715
  execute(tc_members_and_methods());
716 717 718 719 720
  execute(tc_logging());
  execute(tc_equality());
  execute(tc_null());
  execute(tc_this());
  execute(tc_references());
721
  execute(tc_function_pars_and_retval());
722
  execute(tc_function_pars_in());
723
  execute(tc_object());
724
  execute(tc_abstract());
725
  execute(tc_destructor());
726 727 728
  execute(tc_of_operator());
  execute(tc_select_class());
  execute(tc_casting());
729 730 731
}

}