/******************************************************************************
 * Copyright (c) 2000-2025 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:
 *   Baranyi, Botond – initial implementation
 *
 ******************************************************************************/
module OpenTypeTests {

import from Types all;
import from Tools all;

// unaligned
external function enc_er(in ErrorReturn x) return bitstring with { extension "prototype(convert) encode(PER)" }

external function dec_er(in bitstring x) return ErrorReturn with { extension "prototype(convert) decode(PER) errorbehavior(ALL:ERROR)" }

// aligned
external function enc_er_a(in ErrorReturn x) return bitstring with { extension "prototype(convert) encode(PER:ALIGNED)" }

external function dec_er_a(in bitstring x) return ErrorReturn with { extension "prototype(convert) decode(PER:ALIGNED)" }

testcase tc_per_open_type_encode_unaligned() runs on CT {
  // ErrorReturn is a sequence with an embedded open type
  var ErrorReturn x1 := { "A", { { 1, { iNTEGER := 21 } }, { 2, { rEAL := 12.3 } } } };
  var bitstring enc_exp := '1110000010000001000000001000000010000001000000001000101010000000100000010000010010000100000000011001100010011001000110011001011100100010100101101001100010000000'B;
  var bitstring enc := enc_er(x1);
  if (enc != enc_exp) {
    setverdict(fail, "Encoding open type #1 failed. Got: ", enc, ", expected: ", enc_exp);
  }
  var ErrorReturn x2 := { "B", { { 1, { cHARACTER_STRING := { { fixed := NULL }, omit, '1234'O } } }, { 2, { generalString := "John" } } } };
  enc_exp := '111000010000000100000000100000001000001001010000001000010010001101000000000000001000000100000010100000100010010100110111101101000011011100000000'B;
  enc := enc_er(x2);
  if (enc != enc_exp) {
    setverdict(fail, "Encoding open type #2 failed. Got: ", enc, ", expected: ", enc_exp);
  }
  var ErrorReturn x3 := { "B", omit };
  enc_exp := '1010000100000000'B;
  enc := enc_er(x3);
  if (enc != enc_exp) {
    setverdict(fail, "Encoding open type #3 failed. Got: ", enc, ", expected: ", enc_exp);
  }
  
  // this is successfully encoded, but generates an invalid bit-map that can't be decoded
  var ErrorReturn x4 := { omit, { {1, { iNTEGER := 21 } } } };
  enc_exp := '01000000010000000100000001000000100000000100010101000000'B;
  enc := enc_er(x4);
  if (enc != enc_exp) {
    setverdict(fail, "Encoding open type #4 failed. Got: ", enc, ", expected: ", enc_exp);
  }
  setverdict(pass);
}

testcase tc_per_open_type_encode_aligned() runs on CT {
  // ErrorReturn is a sequence with an embedded open type
  var ErrorReturn x1 := { "A", { { 1, { iNTEGER := 21 } }, { 2, { rEAL := 12.3 } } } };
  var bitstring enc_exp := '1101000001000000000000100000000100000001000000100000000100010101000000010000001000001001000010000000001100110001001100100011001100101110010001010010110100110001'B;
  var bitstring enc := enc_er_a(x1);
  if (enc != enc_exp) {
    setverdict(fail, "Encoding open type #1 failed. Got: ", enc, ", expected: ", enc_exp);
  }
  var ErrorReturn x2 := { "B", { { 1, { cHARACTER_STRING := { { fixed := NULL }, omit, '1234'O } } }, { 2, { generalString := "John" } } } };
  enc_exp := '110100001000000000000010000000010000000100000100101000000000001000010010001101000000000100000010000001010000010001001010011011110110100001101110'B;
  enc := enc_er_a(x2);
  if (enc != enc_exp) {
    setverdict(fail, "Encoding open type #2 failed. Got: ", enc, ", expected: ", enc_exp);
  }
  var ErrorReturn x3 := { "B", omit };
  enc_exp := '1001000010000000'B;
  enc := enc_er_a(x3);
  if (enc != enc_exp) {
    setverdict(fail, "Encoding open type #3 failed. Got: ", enc, ", expected: ", enc_exp);
  }
  
  // this is successfully encoded, but generates an invalid bit-map that can't be decoded
  var ErrorReturn x4 := { omit, { {1, { iNTEGER := 21 } } } };
  enc_exp := '01000000000000010000000100000001000000100000000100010101'B;
  enc := enc_er_a(x4);
  if (enc != enc_exp) {
    setverdict(fail, "Encoding open type #4 failed. Got: ", enc, ", expected: ", enc_exp);
  }
  setverdict(pass);
}

testcase tc_per_open_type_decode_unaligned() runs on CT {
  // ErrorReturn is a sequence with an embedded open type
  var bitstring enc := '1110000010000001000000001000000010000001000000001000101010000000100000010000010010000100000000011001100010011001000110011001011100100010100101101001100010000000'B;
  var ErrorReturn x1 := dec_er(enc);
  var ErrorReturn x1_exp := { "A", { { 1, { iNTEGER := 21 } }, { 2, { rEAL := 12.3 } } } };
  if (x1 != x1_exp) {
    setverdict(fail, "Decoding open type #1 failed. Got: ", x1, ", expected: ", x1_exp);
  }
  enc := '111000010000000100000000100000001000001001010000001000010010001101000000000000001000000100000010100000100010010100110111101101000011011100000000'B;
  var ErrorReturn x2 := dec_er(enc);
  var ErrorReturn x2_exp := { "B", { { 1, { cHARACTER_STRING := { { fixed := NULL }, omit, '1234'O } } }, { 2, { generalString := "John" } } } };
  if (x2 != x2_exp) {
    setverdict(fail, "Decoding open type #2 failed. Got: ", x2, ", expected: ", x2_exp);
  }
  enc := '1010000100000000'B;
  var ErrorReturn x3 := dec_er(enc);
  var ErrorReturn x3_exp := { "B", omit };
  if (x3 != x3_exp) {
    setverdict(fail, "Decoding open type #3 failed. Got: ", x3, ", expected: ", x3_exp);
  }
  setverdict(pass);
}

testcase tc_per_open_type_decode_aligned() runs on CT {
  // ErrorReturn is a sequence with an embedded open type
  var bitstring enc := '1101000001000000000000100000000100000001000000100000000100010101000000010000001000001001000010000000001100110001001100100011001100101110010001010010110100110001'B;
  var ErrorReturn x1 := dec_er_a(enc);
  var ErrorReturn x1_exp := { "A", { { 1, { iNTEGER := 21 } }, { 2, { rEAL := 12.3 } } } };
  if (x1 != x1_exp) {
    setverdict(fail, "Decoding open type #1 failed. Got: ", x1, ", expected: ", x1_exp);
  }
  enc := '110100001000000000000010000000010000000100000100101000000000001000010010001101000000000100000010000001010000010001001010011011110110100001101110'B;
  var ErrorReturn x2 := dec_er_a(enc);
  var ErrorReturn x2_exp := { "B", { { 1, { cHARACTER_STRING := { { fixed := NULL }, omit, '1234'O } } }, { 2, { generalString := "John" } } } };
  if (x2 != x2_exp) {
    setverdict(fail, "Decoding open type #2 failed. Got: ", x2, ", expected: ", x2_exp);
  }
  enc := '1001000010000000'B;
  var ErrorReturn x3 := dec_er_a(enc);
  var ErrorReturn x3_exp := { "B", omit };
  if (x3 != x3_exp) {
    setverdict(fail, "Decoding open type #3 failed. Got: ", x3, ", expected: ", x3_exp);
  }
  setverdict(pass);
}

testcase tc_per_open_type_negtest() runs on CT {
  var ErrorReturn x := { "B", { { 1, - } } };
  var bitstring buf;
  @try {
    buf := enc_er(x);
    setverdict(fail, "Open type #1 encoded successfully.");
  }
  @catch (msg) {
    if (not match(msg, pattern "*Encoding an unbound open type value.")) {
      setverdict(fail, "Invalid error message received (#1): ", msg);
    }
  }
  buf := '01000000010000000100000001000000100000000100010101000000'B;
  @try {
    x := dec_er(buf);
    setverdict(fail, "Open type #2 decoded successfully.");
  }
  @catch (msg) {
    if (not match(msg, pattern "*Using the value of an optional field containing omit.")) {
      setverdict(fail, "Invalid error message received (#2): ", msg);
    }
  }
  buf := '1111101100000000100000001000000010000001000000001000101010000000'B;
  @try {
    x := dec_er(buf);
    setverdict(fail, "Open type #3 decoded successfully.");
  }
  @catch (msg) {
    if (not match(msg, pattern "*Cannot decode open type: broken component relation constraint.")) {
      setverdict(fail, "Invalid error message received (#3): ", msg);
    }
  }
  setverdict(pass);
}
  
control {
  execute(tc_per_open_type_encode_unaligned());
  execute(tc_per_open_type_encode_aligned());
  execute(tc_per_open_type_decode_unaligned());
  execute(tc_per_open_type_decode_aligned());
  execute(tc_per_open_type_negtest());
}

}
