/******************************************************************************
 * 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:
 *   Balasko, Jeno
 *   Raduly, Csaba
 *
 ******************************************************************************/
module DFETest {

import from Flattener { function flatten }

modulepar boolean DFETest_verbose := false;
#define verbose DFETest_verbose
#include "../macros.ttcnin"

type component dfe_CT
{}

type charstring dfestring
with {
  variant "defaultForEmpty as 'empty'"
}

DECLARE_XER_ENCODERS (dfestring, dfe);
DECLARE_EXER_ENCODERS(dfestring, dfe);

const dfestring foo := "foo!";
const universal charstring foo_bxer :=
"<dfestring>foo!</dfestring>\n\n";
//const universal charstring foo_exer := foo_bxer; // encode the same way

const dfestring empty := "empty";
const universal charstring empty_bxer := "<dfestring>empty</dfestring>\n\n";
const universal charstring empty_exer_dec := // not the same as BXER anymore
"<dfestring/>\n\n";
const universal charstring empty_exer_dec2 := // not the same as BXER anymore
"<dfestring></dfestring>\n\n";

testcase encode_dfestring() runs on dfe_CT
{
  // encode some value
  CHECK_METHOD(bxer_enc_dfe, foo, foo_bxer);
  CHECK_METHOD(exer_enc_dfe, foo, foo_bxer);

  // encode the default value
  CHECK_METHOD(bxer_enc_dfe, empty, empty_bxer);
  CHECK_METHOD(exer_enc_dfe, empty, empty_bxer);
}

testcase decode_dfestring() runs on dfe_CT
{
  CHECK_DECODE(bxer_dec_dfe, foo_bxer, dfestring, foo);
  CHECK_DECODE(exer_dec_dfe, foo_bxer, dfestring, foo);

  CHECK_DECODE(bxer_dec_dfe, empty_bxer, dfestring, empty);
  CHECK_DECODE(exer_dec_dfe, empty_bxer, dfestring, empty);
  CHECK_DECODE(exer_dec_dfe, empty_exer_dec, dfestring, empty);
  CHECK_DECODE(exer_dec_dfe, empty_exer_dec2, dfestring, empty);
}

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

type universal charstring dfeustring
with {
  variant "defaultForEmpty as 'empty'"
}

DECLARE_XER_ENCODERS (dfeustring, dfeu);
DECLARE_EXER_ENCODERS(dfeustring, dfeu);

const dfeustring ufoo := "foo!";
const universal charstring ufoo_bxer   := "<dfeustring>foo!</dfeustring>\n\n";
//const universal charstring ufoo_exer := ufoo_bxer;

const dfeustring uempty := "empty";
const universal charstring uempty_bxer := "<dfeustring>empty</dfeustring>\n\n";
const universal charstring uempty_exer := // not the same as BXER anymore
"<dfeustring/>\n\n";
const universal charstring uempty_exer2 := // not the same as BXER anymore
"<dfeustring></dfeustring>\n\n";

testcase encode_dfeustring() runs on dfe_CT
{
  CHECK_METHOD(bxer_enc_dfeu, ufoo, ufoo_bxer);
  CHECK_METHOD(exer_enc_dfeu, ufoo, ufoo_bxer);

  CHECK_METHOD(bxer_enc_dfeu, uempty, uempty_bxer);
  CHECK_METHOD(exer_enc_dfeu, uempty, uempty_bxer);
}

testcase decode_dfeustring() runs on dfe_CT
{
  CHECK_DECODE(bxer_dec_dfeu, ufoo_bxer, dfeustring, ufoo);
  CHECK_DECODE(exer_dec_dfeu, ufoo_bxer, dfeustring, ufoo);

  CHECK_DECODE(bxer_dec_dfeu, uempty_bxer, dfeustring, uempty);
  CHECK_DECODE(exer_dec_dfeu, uempty_bxer, dfeustring, uempty); // decoding the unmodified version
  CHECK_DECODE(exer_dec_dfeu, uempty_exer, dfeustring, uempty); // decoding the empty content
  CHECK_DECODE(exer_dec_dfeu, uempty_exer2, dfeustring, uempty); // decoding the empty content
}



/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

type record dferec {
  integer i,
  charstring content
}
with {
  variant (i) "attribute";
  variant (content) "defaultForEmpty as 'nothing to see here'"
}

DECLARE_XER_ENCODERS (dferec, dferec);
DECLARE_EXER_ENCODERS(dferec, dferec);

/* Not the default value */
const dferec df1 := {
  i := 1,
  content := ""
}
const universal charstring df1_bxer :=
"<dferec>\n" &
"\t<i>1</i>\n" &
"\t<content/>\n" &
"</dferec>\n\n"
const universal charstring df1_exer :=
"<dferec i='1'>\n" &
"\t<content/>\n" &
"</dferec>\n\n"

/* The default value */
const dferec df0 := {
  i := 0,
  content := "nothing to see here"
}
const universal charstring df0_bxer :=
"<dferec>\n" &
"\t<i>0</i>\n" &
"\t<content>nothing to see here</content>\n" &
"</dferec>\n\n"
const universal charstring df0_exer_enc :=
"<dferec i='0'>\n" &
"\t<content>nothing to see here</content>\n" &
"</dferec>\n\n"
const universal charstring df0_exer_dec :=
"<dferec i='0'>\n" &
"\t<content/>\n" &
"</dferec>\n\n"
const universal charstring df0_exer_dec2 :=
"<dferec i='0'>\n" &
"\t<content></content>\n" &
"</dferec>\n\n"


testcase encode_dferec() runs on dfe_CT
{
  CHECK_METHOD(bxer_enc_dferec, df1, df1_bxer);
  //DTError expected: string with DFE cannot be empty
  //CHECK_METHOD(exer_enc_dferec, df1, df1_exer);

  CHECK_METHOD(bxer_enc_dferec, df0, df0_bxer);
  CHECK_METHOD(exer_enc_dferec, df0, df0_exer_enc /* not omitted */ );
}

testcase decode_dferec() runs on dfe_CT
{
  var dferec expected := df1;
  CHECK_DECODE(bxer_dec_dferec, df1_bxer, dferec, expected);
  expected.content := df0.content;
  CHECK_DECODE(exer_dec_dferec, df1_exer, dferec, expected);
  CHECK_DECODE(exer_dec_dferec, flatten(df1_exer), dferec, expected);

  CHECK_DECODE(bxer_dec_dferec, df0_bxer, dferec, df0);
  // Decode must recognise both omitted and non-omitted form
  CHECK_DECODE(exer_dec_dferec, df0_exer_enc, dferec, df0); // not omitted
  CHECK_DECODE(exer_dec_dferec, flatten(df0_exer_enc), dferec, df0); // not omitted
  CHECK_DECODE(exer_dec_dferec, df0_exer_dec, dferec, df0); // omitted
  CHECK_DECODE(exer_dec_dferec, flatten(df0_exer_dec), dferec, df0); // omitted
  CHECK_DECODE(exer_dec_dferec, df0_exer_dec2, dferec, df0); // omitted
  CHECK_DECODE(exer_dec_dferec, flatten(df0_exer_dec2), dferec, df0); // omitted
}

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

type record dfeurec {
  integer i,
  universal charstring content
}
with {
  variant (i) "attribute";
  variant (content) "defaultForEmpty as 'nothing to see here'"
}

DECLARE_XER_ENCODERS (dfeurec, dfeurec);
DECLARE_EXER_ENCODERS(dfeurec, dfeurec);

const dfeurec dfu1 := {
  i := 1,
  content := ""
}
const universal charstring dfu1_bxer :=
"<dfeurec>\n" &
"\t<i>1</i>\n" &
"\t<content/>\n" &
"</dfeurec>\n\n"
const universal charstring dfu1_exer :=
"<dfeurec i='1'>\n" &
"\t<content/>\n" &
"</dfeurec>\n\n"

const dfeurec dfu0 := {
  i := 0,
  content := "nothing to see here"
}
const universal charstring dfu0_bxer :=
"<dfeurec>\n" &
"\t<i>0</i>\n" &
"\t<content>nothing to see here</content>\n" &
"</dfeurec>\n\n"
const universal charstring dfu0_exer_enc :=
"<dfeurec i='0'>\n" &
"\t<content>nothing to see here</content>\n" &
"</dfeurec>\n\n"
const universal charstring dfu0_exer_dec :=
"<dfeurec i='0'>\n" &
"\t<content/>\n" &
"</dfeurec>\n\n"
const universal charstring dfu0_exer_dec2 :=
"<dfeurec i='0'>\n" &
"\t<content></content>\n" &
"</dfeurec>\n\n"

testcase encode_dfeurec() runs on dfe_CT
{
  CHECK_METHOD(bxer_enc_dfeurec, dfu1, dfu1_bxer);
  //DTError expected: string with DFE cannot be empty
  //CHECK_METHOD(exer_enc_dfeurec, dfu1, dfu1_exer);

  CHECK_METHOD(bxer_enc_dfeurec, dfu0, dfu0_bxer);
  CHECK_METHOD(exer_enc_dfeurec, dfu0, dfu0_exer_enc); // not omitted
}

testcase decode_dfeurec() runs on dfe_CT
{
  var dfeurec expected := dfu1;
  CHECK_DECODE(bxer_dec_dfeurec, dfu1_bxer, dfeurec, expected);
  expected.content := dfu0.content;
  CHECK_DECODE(exer_dec_dfeurec, dfu1_exer, dfeurec, expected);
  CHECK_DECODE(exer_dec_dfeurec, flatten(dfu1_exer), dfeurec, expected);

  CHECK_DECODE(bxer_dec_dfeurec, dfu0_bxer, dfeurec, dfu0);
  CHECK_DECODE(exer_dec_dfeurec, dfu0_exer_enc, dfeurec, dfu0); // not omitted 
  CHECK_DECODE(exer_dec_dfeurec, flatten(dfu0_exer_enc), dfeurec, dfu0); // not omitted 
  CHECK_DECODE(exer_dec_dfeurec, dfu0_exer_dec, dfeurec, dfu0); // omitted
  CHECK_DECODE(exer_dec_dfeurec, flatten(dfu0_exer_dec), dfeurec, dfu0); // omitted
  CHECK_DECODE(exer_dec_dfeurec, dfu0_exer_dec2, dfeurec, dfu0); // omitted
  CHECK_DECODE(exer_dec_dfeurec, flatten(dfu0_exer_dec2), dfeurec, dfu0); // omitted
}

/* * * * * * * * * * * * * * INTEGER * * * * * * * * * * * * * * * * */

type record dfeint {
  integer lucky
}
with {
  variant (lucky) "defaultForEmpty as '13'"
}

DECLARE_XER_ENCODERS(dfeint, dfi);
DECLARE_EXER_ENCODERS(dfeint, dfi);

const dfeint luxor := {
  lucky := 31 // a lucky prime
}

const universal charstring bstr_luxor :=
"<dfeint>\n" &
"\t<lucky>31</lucky>\n" &
"</dfeint>\n\n";

const universal charstring estr_luxor := bstr_luxor;

const dfeint pech := {
  lucky := 13 // 13 is also a lucky prime
}

const universal charstring bstr_pech :=
"<dfeint>\n" &
"\t<lucky>13</lucky>\n" &
"</dfeint>\n\n";

const universal charstring estr_pech := bstr_pech;
const universal charstring estr_pech_empty :=
"<dfeint>\n" &
"\t<lucky/>\n" &
"</dfeint>\n\n";
const universal charstring estr_pech_empty2 :=
"<dfeint>\n" &
"\t<lucky></lucky>\n" &
"</dfeint>\n\n";


testcase encode_dfeint() runs on dfe_CT
{
  CHECK_METHOD(bxer_enc_dfi, luxor, bstr_luxor);
  CHECK_METHOD(exer_enc_dfi, luxor, estr_luxor);

  CHECK_METHOD(bxer_enc_dfi, pech, bstr_pech);
  CHECK_METHOD(exer_enc_dfi, pech, estr_pech);
}

testcase decode_dfeint() runs on dfe_CT
{
  CHECK_DECODE(bxer_dec_dfi, bstr_luxor, dfeint, luxor);
  CHECK_DECODE(exer_dec_dfi, estr_luxor, dfeint, luxor);
  CHECK_DECODE(exer_dec_dfi, flatten(estr_luxor), dfeint, luxor);

  CHECK_DECODE(bxer_dec_dfi, bstr_pech, dfeint, pech); // bxer not omitted
  CHECK_DECODE(exer_dec_dfi, estr_pech, dfeint, pech); // exer  ---"---
  CHECK_DECODE(exer_dec_dfi, flatten(estr_pech), dfeint, pech); // exer  ---"---

  CHECK_DECODE(exer_dec_dfi, estr_pech_empty, dfeint, pech); // exer omitted
  CHECK_DECODE(exer_dec_dfi, flatten(estr_pech_empty), dfeint, pech); // exer omitted
  CHECK_DECODE(exer_dec_dfi, estr_pech_empty2, dfeint, pech); // exer omitted
  CHECK_DECODE(exer_dec_dfi, flatten(estr_pech_empty2), dfeint, pech); // exer omitted
}


/* * * * * * * * * * * * * * BOOLEAN * * * * * * * * * * * * * * * * */

type record dfeboolrec { // DFE applied to the record
  boolean lucker
}
with {
  variant "defaultForEmpty as 'true'"
}

DECLARE_XER_ENCODERS(dfeboolrec, dfbr);
DECLARE_EXER_ENCODERS(dfeboolrec, dfbr);

const dfeboolrec bluxor := {
  lucker := false // 
}

const universal charstring bstr_bluxor :=
"<dfeboolrec>\n" &
"\t<lucker><false/></lucker>\n" &
"</dfeboolrec>\n\n";

const universal charstring estr_bluxor :=
"<dfeboolrec>\n" &
"\t<lucker>false</lucker>\n" & // EXER changes it from EmptyElementBoolean to TextBoolean
"</dfeboolrec>\n\n";


const dfeboolrec malac := {
  lucker := true // 
}

const universal charstring bstr_malac :=
"<dfeboolrec>\n" &
"\t<lucker><true/></lucker>\n" &
"</dfeboolrec>\n\n";

const universal charstring estr_malac := 
"<dfeboolrec>\n" &
"\t<lucker>true</lucker>\n" & // EXER changes it from EmptyElementBoolean to TextBoolean
"</dfeboolrec>\n\n";

const universal charstring estr_malac_empty :=
"<dfeboolrec/>\n\n";


testcase encode_dfeboolrec() runs on dfe_CT
{
  CHECK_METHOD(bxer_enc_dfbr, bluxor, bstr_bluxor);
  CHECK_METHOD(exer_enc_dfbr, bluxor, estr_bluxor);

  CHECK_METHOD(bxer_enc_dfbr, malac, bstr_malac);
  CHECK_METHOD(exer_enc_dfbr, malac, estr_malac);
}

testcase decode_dfeboolrec() runs on dfe_CT
{
  CHECK_DECODE(bxer_dec_dfbr, bstr_bluxor, dfeboolrec, bluxor);
  CHECK_DECODE(exer_dec_dfbr, estr_bluxor, dfeboolrec, bluxor);
  CHECK_DECODE(exer_dec_dfbr, flatten(estr_bluxor), dfeboolrec, bluxor);

  CHECK_DECODE(bxer_dec_dfbr, bstr_malac, dfeboolrec, malac); // bxer not omitted
  CHECK_DECODE(exer_dec_dfbr, estr_malac, dfeboolrec, malac); // exer  ---"---
  CHECK_DECODE(exer_dec_dfbr, flatten(estr_malac), dfeboolrec, malac); // exer  ---"---

  CHECK_DECODE(exer_dec_dfbr, estr_malac_empty, dfeboolrec, malac); // exer omitted
  CHECK_DECODE(exer_dec_dfbr, flatten(estr_malac_empty), dfeboolrec, malac); // exer omitted
}



/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

type record dfebool { // DFE applied to the field
  boolean lucker
}
with {
  variant (lucker) "defaultForEmpty as 'true'"
}

DECLARE_XER_ENCODERS(dfebool, dfb);
DECLARE_EXER_ENCODERS(dfebool, dfb);

const dfebool bluxorf := {
  lucker := false // 
}

const universal charstring bstr_bluxorf :=
"<dfebool>\n" &
"\t<lucker><false/></lucker>\n" &
"</dfebool>\n\n";

const universal charstring estr_bluxorf :=
"<dfebool>\n" &
"\t<lucker>false</lucker>\n" & // EXER changes it from EmptyElementBoolean to TextBoolean
"</dfebool>\n\n";


const dfebool malacf := {
  lucker := true // 
}

const universal charstring bstr_malacf :=
"<dfebool>\n" &
"\t<lucker><true/></lucker>\n" &
"</dfebool>\n\n";

const universal charstring estr_malacf := 
"<dfebool>\n" &
"\t<lucker>true</lucker>\n" & // EXER changes it from EmptyElementBoolean to TextBoolean
"</dfebool>\n\n";

const universal charstring estr_malac_emptyf :=
"<dfebool>\n" &
"\t<lucker/>\n" &
"</dfebool>\n\n";



testcase encode_dfebool() runs on dfe_CT
{
  CHECK_METHOD(bxer_enc_dfb, bluxorf, bstr_bluxorf);
  CHECK_METHOD(exer_enc_dfb, bluxorf, estr_bluxorf);

  CHECK_METHOD(bxer_enc_dfb, malacf, bstr_malacf);
  CHECK_METHOD(exer_enc_dfb, malacf, estr_malacf);
}

testcase decode_dfebool() runs on dfe_CT
{
  CHECK_DECODE(bxer_dec_dfb, bstr_bluxorf, dfebool, bluxorf);
  CHECK_DECODE(exer_dec_dfb, estr_bluxorf, dfebool, bluxorf);
  CHECK_DECODE(exer_dec_dfb, flatten(estr_bluxorf), dfebool, bluxorf);

  CHECK_DECODE(bxer_dec_dfb, bstr_malacf, dfebool, malacf); // bxer not omitted
  CHECK_DECODE(exer_dec_dfb, estr_malacf, dfebool, malacf); // exer  ---"---
  CHECK_DECODE(exer_dec_dfb, flatten(estr_malacf), dfebool, malacf); // exer  ---"---

  CHECK_DECODE(exer_dec_dfb, estr_malac_emptyf, dfebool, malacf); // exer omitted
  CHECK_DECODE(exer_dec_dfb, flatten(estr_malac_emptyf), dfebool, malacf); // exer omitted
}

/* * * * * * * FLOAT * * * * * * * */

type record dfef {
  // not suported for DFE bitstring itsy_bitsy
  float f
}
with {
  variant (f) "defaultForEmpty as '3.14159'"
}

DECLARE_XER_ENCODERS(dfef, dfef);
DECLARE_EXER_ENCODERS(dfef, dfef);

const dfef c_df1 := {
  f := 7.2
}
const universal charstring bstr_df1 :=
"<dfef>\n" &
"\t<f>7.200000</f>\n" &
"</dfef>\n\n";

const dfef c_df3 := {
  f := 3.14159 // the default value
}

const universal charstring bstr_df3 :=
"<dfef>\n" &
"\t<f>3.141590</f>\n" &
"</dfef>\n\n";

const universal charstring estr_df3 :=
"<dfef>\n" &
"\t<f></f>\n" &
"</dfef>\n\n";

const universal charstring estr_df3empty :=
"<dfef>\n" &
"\t<f/>\n" &
"</dfef>\n\n";


testcase encode_dfef() runs on dfe_CT
{
  CHECK_METHOD(bxer_enc_dfef, c_df1, bstr_df1);
  CHECK_METHOD(exer_enc_dfef, c_df1, bstr_df1);

  CHECK_METHOD(bxer_enc_dfef, c_df3, bstr_df3);
  CHECK_METHOD(exer_enc_dfef, c_df3, bstr_df3);
}

testcase decode_dfef() runs on dfe_CT
{
  CHECK_DECODE(bxer_dec_dfef, bstr_df1, dfef, c_df1);
  CHECK_DECODE(exer_dec_dfef, bstr_df1, dfef, c_df1);
  CHECK_DECODE(exer_dec_dfef, flatten(bstr_df1), dfef, c_df1);

  CHECK_DECODE(bxer_dec_dfef, bstr_df3, dfef, c_df3);
  CHECK_DECODE(exer_dec_dfef, bstr_df1, dfef, c_df1);
  CHECK_DECODE(exer_dec_dfef, flatten(bstr_df1), dfef, c_df1);
  
  CHECK_DECODE(exer_dec_dfef, estr_df3, dfef, c_df3); // empty content
  CHECK_DECODE(exer_dec_dfef, flatten(estr_df3), dfef, c_df3); // empty content
  CHECK_DECODE(exer_dec_dfef, estr_df3empty, dfef, c_df3); // empty element
  CHECK_DECODE(exer_dec_dfef, flatten(estr_df3empty), dfef, c_df3); // empty element
}

/* * * * * * * * * * OCTETSTRING * * * * * * * * * */
/* octetstring can only have DFE if character-encodable,
   which requires XSD:base64Binary
type record dfeorec {
  octetstring os
}
with {
  variant (os) "defaultForEmpty as 'DEADBEEF'"
}

DECLARE_XER_ENCODERS(dfeorec, dfeo);
DECLARE_EXER_ENCODERS(dfeorec, dfeo);

const dfeorec dfo1 := {
  os := 'BABEFACE'O
}
const universal charstring bstr_dfo1 :=
"<dfeorec>\n" &
"\t<os>BABEFACE</os>\n" &
"</dfeorec>\n\n";

const dfeorec dfo0 := {
  os := 'DEADBEEF'O
}
const universal charstring bstr_dfo0 :=
"<dfeorec>\n" &
"\t<os>DEADBEEF</os>\n" &
"</dfeorec>\n\n";

const universal charstring estr_dfo0 := // EXER decoding only
"<dfeorec>\n" &
"\t<os></os>\n" &
"</dfeorec>\n\n";

const universal charstring estr_dfo02 := // EXER decoding only
"<dfeorec>\n" &
"\t<os/>\n" &
"</dfeorec>\n\n";

testcase encode_dfeos() runs on dfe_CT
{
  CHECK_METHOD(bxer_enc_dfeo, dfo1, bstr_dfo1);
  CHECK_METHOD(exer_enc_dfeo, dfo1, bstr_dfo1); // EXER encodes the same 
  CHECK_METHOD(bxer_enc_dfeo, dfo0, bstr_dfo0);
  CHECK_METHOD(exer_enc_dfeo, dfo0, bstr_dfo0); // EXER encodes the same 
}

testcase decode_dfeos() runs on dfe_CT
{
  CHECK_DECODE(bxer_dec_dfeo, bstr_dfo1, dfeorec, dfo1);
  CHECK_DECODE(exer_dec_dfeo, bstr_dfo1, dfeorec, dfo1);
  
  CHECK_DECODE(bxer_dec_dfeo, bstr_dfo0, dfeorec, dfo0);
  CHECK_DECODE(exer_dec_dfeo, bstr_dfo0, dfeorec, dfo0); // decode the unmodified
  CHECK_DECODE(exer_dec_dfeo, estr_dfo0, dfeorec, dfo0); // decode empty content
  CHECK_DECODE(exer_dec_dfeo, estr_dfo02,dfeorec, dfo0); // decode empty element tag
}
*/
control {
  execute(encode_dfestring());
  execute(decode_dfestring());
  execute(encode_dfeustring());
  execute(decode_dfeustring());

  execute(encode_dferec());
  execute(decode_dferec());
  execute(encode_dfeurec());
  execute(decode_dfeurec());

  execute(encode_dfeint());
  execute(decode_dfeint());

  execute(encode_dfeboolrec());
  execute(decode_dfeboolrec());

  execute(encode_dfebool());
  execute(decode_dfebool());

  execute(encode_dfef());
  execute(decode_dfef());

//  execute(encode_dfeos());
//  execute(decode_dfeos());
}

}
with {
encode "XML"
}
