/******************************************************************************
 * 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:
 *   Balasko, Jeno
 *   Raduly, Csaba
 *   Szabo, Bence Janos
 *
 ******************************************************************************/
module Txerfloat {

modulepar boolean Txerfloat_verbose := false;
#define verbose Txerfloat_verbose

#include "../macros.ttcnin"

import from AsnValues all;
type component TFLOAT {}

external function flatten(inout universal charstring par) ;

DECLARE_XER_ENCODERS( float,  float);
DECLARE_EXER_ENCODERS(float,  float);
DECLARE_XER_ENCODERS(rfloat, rfloat);
DECLARE_EXER_ENCODERS(rfloat,rfloat)
DECLARE_XER_ENCODERS(ufloat, ufloat);
DECLARE_EXER_ENCODERS(ufloat,ufloat)
DECLARE_XER_ENCODERS(attrfloat, attrfloat);
DECLARE_EXER_ENCODERS(attrfloat, attrfloat)

type record rfloat {
  float f optional
}

type union ufloat {
  float f
}

type record attrfloat {
    float f optional
}
with {
  variant (f) "attribute"
}

testcase encode_float() runs on TFLOAT
{
    var float plain         :=        3.141592;
    var universal charstring expected := "<REAL>3.141592</REAL>";
    CHECK_METHOD(cxer_enc_float, plain, expected);
    CHECK_METHOD(bxer_enc_float, plain, expected & lf);
    CHECK_METHOD(exer_enc_float, plain, expected & lf);

    plain :=           -2.718281828459045;
    expected := "<REAL>-2.718282</REAL>"
    CHECK_METHOD(cxer_enc_float, plain, expected);
    CHECK_METHOD(bxer_enc_float, plain, expected & lf);
    CHECK_METHOD(exer_enc_float, plain, expected & lf);

    plain := 0.0;
    expected := "<REAL>0.000000</REAL>";
    CHECK_METHOD(cxer_enc_float, plain, expected);
    CHECK_METHOD(bxer_enc_float, plain, expected & lf);
    CHECK_METHOD(exer_enc_float, plain, expected & lf);

    plain := -0.0;
    expected := "<REAL>-0.000000</REAL>";
    CHECK_METHOD(cxer_enc_float, plain, expected);
    CHECK_METHOD(bxer_enc_float, plain, expected & lf);
    CHECK_METHOD(exer_enc_float, plain, expected & lf);

    plain := infinity;
    expected := "<REAL>INF</REAL>";
    CHECK_METHOD(cxer_enc_float, plain, expected);
    CHECK_METHOD(bxer_enc_float, plain, expected & lf);
    CHECK_METHOD(exer_enc_float, plain, expected & lf);

    plain := -infinity;
    expected := "<REAL>-INF</REAL>";
    CHECK_METHOD(cxer_enc_float, plain, expected);
    CHECK_METHOD(bxer_enc_float, plain, expected & lf);
    CHECK_METHOD(exer_enc_float, plain, expected & lf);

    plain := not_a_number;
    expected := "<REAL>NaN</REAL>";
    CHECK_METHOD(cxer_enc_float, plain, expected);
    CHECK_METHOD(bxer_enc_float, plain, expected & lf);
    CHECK_METHOD(exer_enc_float, plain, expected & lf);
}

testcase decode_float() runs on TFLOAT
{
	const charstring pie := "<REAL>3.141592</REAL>";
	var float expected   :=        3.141592;
    CHECK_DECODE(cxer_dec_float, pie, float, expected);
    CHECK_DECODE(bxer_dec_float, pie, float, expected);

    // causes rounding errors :   -2.718281828459045
    var charstring ee := "<REAL>-2.7182818284590</REAL>";
    expected :=                   -2.7182818284590;
	CHECK_DECODE(cxer_dec_float, ee, float, expected);
	CHECK_DECODE(bxer_dec_float, ee, float, expected);

    ee := "<REAL>INF</REAL>";
    expected :=                   infinity;
    CHECK_DECODE(cxer_dec_float, ee, float, expected);
    CHECK_DECODE(bxer_dec_float, ee, float, expected);

    ee := "<REAL>-INF</REAL>";
    expected :=                   -infinity;
    CHECK_DECODE(cxer_dec_float, ee, float, expected);
    CHECK_DECODE(bxer_dec_float, ee, float, expected);

    ee := "<REAL>NaN</REAL>";
    expected :=                   not_a_number;
    CHECK_DECODE(cxer_dec_float, ee, float, expected);
    CHECK_DECODE(bxer_dec_float, ee, float, expected);
}

testcase encode_float_omit() runs on TFLOAT
{
	var rfloat rec := { omit }
	var universal charstring expected;

	expected := "<rfloat/>\n";
    CHECK_METHOD(cxer_enc_rfloat, rec, expected);
    CHECK_METHOD(bxer_enc_rfloat, rec, expected & lf);
    CHECK_METHOD(exer_enc_rfloat, rec, expected & lf);

    rec.f := 2.718282;
    expected := "<rfloat>\n\t<f>2.718282</f>\n</rfloat>\n\n";
    CHECK_METHOD(bxer_enc_rfloat, rec, expected);
    CHECK_METHOD(exer_enc_rfloat, rec, expected);
    flatten(expected);
    CHECK_METHOD(cxer_enc_rfloat, rec, expected & lf);
}

testcase decode_float_omit() runs on TFLOAT
{
	const charstring omitted := "<rfloat/>\n";
	var rfloat expected := { omit }
	CHECK_DECODE(cxer_dec_rfloat, omitted, rfloat, expected);
	CHECK_DECODE(bxer_dec_rfloat, omitted, rfloat, expected);

	const charstring supplied := "<rfloat>\n\t<f>2.718282</f>\n</rfloat>\n\n";
	expected := { 2.718282 };
	CHECK_DECODE(cxer_dec_rfloat, supplied, rfloat, expected);
	CHECK_DECODE(bxer_dec_rfloat, supplied, rfloat, expected);
}

testcase encode_float_choice() runs on TFLOAT
{
	var ufloat rec := { f := 666.666 }
	var universal charstring expected;

    expected := "<ufloat>\n\t<f>666.666000</f>\n</ufloat>\n\n";
    CHECK_METHOD(bxer_enc_ufloat, rec, expected);
    CHECK_METHOD(exer_enc_ufloat, rec, expected);
    flatten(expected);
    CHECK_METHOD(cxer_enc_ufloat, rec, expected & lf);

    rec.f := -1.602176487E-19; // one electron
    expected := "<ufloat>\n\t<f>-1.602176e-19</f>\n</ufloat>\n\n";
    CHECK_METHOD(bxer_enc_ufloat, rec, expected);
    CHECK_METHOD(exer_enc_ufloat, rec, expected);
    flatten(expected);
    CHECK_METHOD(cxer_enc_ufloat, rec, expected & lf);
}

testcase decode_float_choice() runs on TFLOAT
{
	const charstring electron := "<ufloat>\n\t<f>-1.602176487E-19</f>\n</ufloat>\n\n";
	var ufloat expected       := { f :=          -1.602176487E-19 };
	CHECK_DECODE(cxer_dec_ufloat, electron, ufloat, expected);
	CHECK_DECODE(bxer_dec_ufloat, electron, ufloat, expected);
}

testcase encode_float_attribute() runs on TFLOAT
{
    var attrfloat plain := { f := infinity };
    var universal charstring expected := "<attrfloat f='INF'/>\n";
    CHECK_METHOD(exer_enc_attrfloat, plain, expected & lf);

    plain := { f := -infinity }
    expected := "<attrfloat f='-INF'/>\n";
    CHECK_METHOD(exer_enc_attrfloat, plain, expected & lf);

    plain := { f := not_a_number }
    expected := "<attrfloat f='NaN'/>\n";
    CHECK_METHOD(exer_enc_attrfloat, plain, expected & lf);
}

testcase decode_float_attribute() runs on TFLOAT
{
    var attrfloat expected := { f := infinity };
    var universal charstring plain := "<attrfloat f='INF'/>\n";
    CHECK_DECODE(exer_dec_attrfloat, plain, attrfloat, expected);

    expected := { f := -infinity }
    plain := "<attrfloat f='-INF'/>\n";
    CHECK_DECODE(exer_dec_attrfloat, plain, attrfloat, expected);

    expected := { f := not_a_number }
    plain := "<attrfloat f='NaN'/>\n";
    CHECK_DECODE(exer_dec_attrfloat, plain, attrfloat, expected);
}



control {
	execute(encode_float());
	execute(decode_float());
	execute(encode_float_omit())
	execute(decode_float_omit())
	execute(encode_float_choice());
	execute(decode_float_choice());
	execute(encode_float_attribute());
	execute(decode_float_attribute());
}

}
with {
  encode "XML";
  extension "version R8F";
}
