<?xml version="1.0" encoding="UTF-8"?>

<!--================================================================-->
<!-- Copyright 2003 P&P Software GmbH             -->
<!--================================================================-->

<!--===================================================================
Generator meta-component for the test case for the indexed parameter
database class of the OBS Framework.

This XSL program generates the body file of the parameter database
test case class.

This XSL program processes the XML-based application model.
===================================================================-->

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.1">

<xsl:strip-space elements="*"/>
<xsl:output omit-xml-declaration="yes" method="text"/>

<!--===================================================================
       Include general utility rules
===================================================================-->
 <xsl:include href="ClassNameFromPath.xsl"/>
 <xsl:include href="ClassIdFromClassName.xsl"/>
<xsl:include href="WriteCommentBody.xsl"/>
<xsl:include href="MakeFirstLetterCap.xsl"/>
<!--===================================================================
      Top-level rule 
===================================================================-->
<xsl:template match="/ObsApplication/ParameterDatabase/IndexedDatabase">
<!--===================================================================
      Define general-purpose variables
 ===================================================================-->  
  <xsl:variable name="ClassName">
        <xsl:call-template name="ClassNameFromPath">
              <xsl:with-param name="path" select="@type"/>
        </xsl:call-template>
  </xsl:variable>
  <xsl:variable name="ClassId">
        <xsl:call-template name="ClassIdFromClassName">
              <xsl:with-param name="className" select="$ClassName"/>
        </xsl:call-template>
  </xsl:variable>
  <xsl:variable name="CodeDir" select="'../'"/>
  <xsl:variable name="Level" select="RobustnessLevel/@value"/>

  <!-- construct the name of the test case class                   -->
  <xsl:variable name="TestCaseClassName" select="
    concat('TestCase',substring($ClassName,4,string-length($ClassName)),'_1')"/>

  <!-- compute and store the maximum parameter ID value           -->
  <xsl:variable name="maxParId">
    <xsl:call-template name="computeMaxParId">
       <xsl:with-param name="currentMax" select="0"/>
       <xsl:with-param name="currentPos" select="1"/>
    </xsl:call-template>
  </xsl:variable>

  <!-- compute and store the lowest illegal parameter id          -->
  <xsl:variable name="illegalParId">
    <xsl:call-template name="computeLowestIllegalParId">
       <xsl:with-param name="current" select="1"/>
    </xsl:call-template>
  </xsl:variable>

  <!-- compute and store the database size in bytes.              -->
  <xsl:variable name="dbLength" select="Size/@value"/>

  <!-- start code generation                                       -->
 <xsl:variable name="TargetFile" select="concat('/Projects/ObsFramework/src/cpp/RegressionTest/',$TestCaseClassName)"/>     
            
  Generating code for class <xsl:value-of select="$ClassName"/> in files <xsl:value-of select="$TargetFile"/>.cpp

  <!-- Check whether writing to an output file is possible -->
  <xsl:if test="not(element-available('xsl:document'))">
        FATAL ERROR: the xsl:document element is not supported. Header files cannot be written! This element
        is normally supported only in version 1.1 of XSL.
  </xsl:if>
            
 <!-- ===================================================================================
         Create the output file  
  ===================================================================================-->
  <xsl:document href="{$TargetFile}.cpp" omit-xml-declaration="yes" method="text">  
//
// Copyright 2003 P&amp;P Software GmbH - All Rights Reserved
//
// <xsl:value-of select="$TestCaseClassName"/>.cpp
//
// This file was automatically generated by an XSL program
//

#include "<xsl:value-of select="$CodeDir"/>GeneralInclude/CompilerSwitches.h"
#include "<xsl:value-of select="$CodeDir"/>GeneralInclude/ClassId.h"
#include "<xsl:value-of select="$CodeDir"/>GeneralInclude/Constants.h"
#include "<xsl:value-of select="$CodeDir"/>Data/<xsl:value-of select="$ClassName"/>.h"
#include "<xsl:value-of select="$TestCaseClassName"/>.h"
#include "<xsl:value-of select="$CodeDir"/>Utilities/TestCaseWithEvtCheck.h"

#include &lt;math.h&gt;
#include &lt;float.h&gt;<xsl:text>

</xsl:text>
<xsl:value-of select="$TestCaseClassName"/>::<xsl:value-of select="$TestCaseClassName"/>():
	TestCaseWithEvtCheck(<xsl:value-of select="$ClassId"/>*10+1,"<xsl:value-of select="$TestCaseClassName"/>") {
		return;
}

void <xsl:value-of select="$TestCaseClassName"/>::runTestCase() {

   // Data structures to simulate the default and operational tables
   // (The size of the database is read from the Parameter Database
   // Descriptor file).
   unsigned int dbLength = <xsl:value-of select="$dbLength"/>;
   unsigned char* defaultTable = new unsigned char[dbLength];
   unsigned char* operationalTable = new unsigned char[dbLength];

   // Initialize the default database. Each parameter is given a
   // value equal to its parameter ID. The parameter ID is read from
   // the Parameter Database Descriptor File. Note that this
   // strategy will sometimes result in an attempt to assign to a
   // parameter a value that is inconsistent with its type (e.g. a
   // a parameter of type 'char' might have a parameter ID greater than
   // 256).<xsl:text/>
   unsigned char* uc;
   <xsl:for-each select="Parameter">
   uc = (defaultTable+<xsl:value-of select="Offset/@value"/>);
   *(<xsl:value-of select="Type/@value"/>*)uc = (<xsl:value-of 
                                    select="Type/@value"/>)<xsl:value-of select="Id/@value"/>;<xsl:text/>
   </xsl:for-each>

   // Get current number of events in event repository
   unsigned int nEvt;
   nEvt = getNumberOfEvents();

   // Initialize the operational database to all zeros
   for (unsigned int i=0; i&lt;dbLength; i++)
       operationalTable[i]=0;

   // Instantiate parameter database
   <xsl:value-of select="$ClassName"/>* pDB = new <xsl:value-of select="$ClassName"/>();

   // Variable to hold the maximum parId
   TD_DatabaseId maxParId;
   maxParId = <xsl:value-of select="$maxParId"/>;

   // Variable to hold the lowest illegal parId
   TD_DatabaseId illegalParId;
   illegalParId = <xsl:value-of select="$illegalParId"/>;

   // Verify correctness of class ID
   if (pDB-&gt;getClassId() != <xsl:value-of select="$ClassId"/>)
   {      setTestResult(TEST_FAILURE, "Wrong class ID");
            return;
    }

   // Check that database is not yet configured
   if ( pDB-&gt;isObjectConfigured() != NOT_CONFIGURED )
   {      setTestResult(TEST_FAILURE, "Incorrect configuration status at creation");
            return;
    }

   // Configure database
   pDB-&gt;setDefaultTable((char*)defaultTable);
   pDB-&gt;setOperationalTable((char*)operationalTable);
   pDB-&gt;reset();

   // Check that database is configured
   if ( pDB-&gt;isObjectConfigured() != CONFIGURED )
   {      setTestResult(TEST_FAILURE, "Incorrect configuration status after configuration was completed");
            return;
   }

   // Check the pointer getter methods
   <xsl:for-each select="Parameter">
    <xsl:variable name="nameNoSpaces">
      <xsl:call-template name="makeFirstLetterCap">
        <xsl:with-param name="before" select="''"/>
        <xsl:with-param name="after" select="Type/@value"/>
      </xsl:call-template>
    </xsl:variable>
   if ((unsigned char*)pDB->getParameterPointer<xsl:value-of select="$nameNoSpaces"/>(<xsl:value-of
                select="Id/@value"/>)!=operationalTable+<xsl:value-of select="Offset/@value"/>)
   {      setTestResult(TEST_FAILURE, "Incorrect pointer value for parameter");
            return;
   }</xsl:for-each>

   // Check that non-real paramaters have the correct value
   <xsl:for-each select="Parameter[Type/@value!='float'][Type/@value!='double']">
    <xsl:sort select="Id/@value" data-type="number"/>
    <xsl:variable name="nameNoSpaces">
      <xsl:call-template name="makeFirstLetterCap">
        <xsl:with-param name="before" select="''"/>
        <xsl:with-param name="after" select="Type/@value"/>
      </xsl:call-template>
    </xsl:variable>
   if (pDB->getParameter<xsl:value-of select="$nameNoSpaces"/>(<xsl:value-of
            select="Id/@value"/>)!=(<xsl:value-of select="Type/@value"/>)<xsl:value-of select="Id/@value"/>)
   {      setTestResult(TEST_FAILURE, "Incorrect parameter value");
            return;
   }</xsl:for-each>

   // Check that real parameters have the correct value
   <xsl:for-each select="Parameter[(Type/@value='double') or (Type/@value='float')]">
    <xsl:sort select="Id/@value" data-type="number"/>
    <xsl:variable name="nameNoSpaces">
      <xsl:call-template name="makeFirstLetterCap">
        <xsl:with-param name="before" select="''"/>
        <xsl:with-param name="after" select="Type/@value"/>
      </xsl:call-template>
    </xsl:variable>
   if (fabs(pDB->getParameter<xsl:value-of select="$nameNoSpaces"/>(<xsl:value-of
            select="Id/@value"/>)-<xsl:value-of select="Id/@value"/>) &gt; DBL_EPSILON)
   {      setTestResult(TEST_FAILURE, "Incorrect value for parameter");
            return;
   }</xsl:for-each>

   // Update the value of all parameters by setting it equal to their (parId+1)
   <xsl:for-each select="Parameter">
    <xsl:sort select="Id/@value" data-type="number"/>
   pDB->setParameter(<xsl:value-of select="Id/@value"/>,(<xsl:value-of
        select="Type/@value"/>)(<xsl:value-of select="Id/@value"/>+1)); <xsl:text/>
   </xsl:for-each>

   // Check that non-real paramaters have the correct value
   <xsl:for-each select="Parameter[Type/@value!='float'][Type/@value!='double']">
    <xsl:sort select="Id/@value" data-type="number"/>
    <xsl:variable name="nameNoSpaces">
      <xsl:call-template name="makeFirstLetterCap">
        <xsl:with-param name="before" select="''"/>
        <xsl:with-param name="after" select="Type/@value"/>
      </xsl:call-template>
    </xsl:variable>
   if (pDB->getParameter<xsl:value-of select="$nameNoSpaces"/>(<xsl:value-of
        select="Id/@value"/>)!=(<xsl:value-of select="Type/@value"/>)(<xsl:value-of select="Id/@value"/>+1))
   {      setTestResult(TEST_FAILURE, "Incorrect value for parameter <xsl:value-of select="Id/@value"/>");
            return;
   }<xsl:text/>
   </xsl:for-each>

   // Check that real paramaters have the correct value
   <xsl:for-each select="Parameter[(Type/@value='float') or (Type/@value='double')]">
    <xsl:sort select="Id/@value" data-type="number"/>
    <xsl:variable name="nameNoSpaces">
      <xsl:call-template name="makeFirstLetterCap">
        <xsl:with-param name="before" select="''"/>
        <xsl:with-param name="after" select="Type/@value"/>
      </xsl:call-template>
    </xsl:variable>
   if (fabs(pDB->getParameter<xsl:value-of select="$nameNoSpaces"/>(<xsl:value-of
            select="Id/@value"/>)-(<xsl:value-of select="Id/@value"/>+1)) &gt; DBL_EPSILON)
   {      setTestResult(TEST_FAILURE, "Incorrect value for parameter <xsl:value-of select="Id/@value"/>");
            return;
   } <xsl:text/>
   </xsl:for-each>

   <xsl:if test="$Level!=1">
   // Check the setter and pointer methods generate event reports when they are accessed either
   // with an out-of-range parameter value or with an illegal parameter value
   if (isNonNominalCheckAllowed()) {
        char* dummy_1;
<xsl:call-template name="Level23Check">
   <xsl:with-param name="type" select="'int'"/>
</xsl:call-template>   
<xsl:call-template name="Level23Check">
   <xsl:with-param name="type" select="'unsigned int'"/>
</xsl:call-template>
<xsl:call-template name="Level23Check">
   <xsl:with-param name="type" select="'short'"/>
</xsl:call-template>
<xsl:call-template name="Level23Check">
   <xsl:with-param name="type" select="'unsigned short'"/>
</xsl:call-template>
<xsl:call-template name="Level23Check">
   <xsl:with-param name="type" select="'char'"/>
</xsl:call-template>
<xsl:call-template name="Level23Check">
   <xsl:with-param name="type" select="'unsigned char'"/>
</xsl:call-template>
<xsl:call-template name="Level23Check">
   <xsl:with-param name="type" select="'bool'"/>
</xsl:call-template>
<xsl:call-template name="Level23Check">
   <xsl:with-param name="type" select="'float'"/>
</xsl:call-template>
<xsl:call-template name="Level23Check">
   <xsl:with-param name="type" select="'double'"/>
</xsl:call-template>
    }
    </xsl:if>

   <xsl:if test="$Level=3">
   // Check the getter methods generate errors when they are accessed either
   // with an out-of-range parameter value or with an illegal parameter value
   if (isNonNominalCheckAllowed()) {
        double dummy_2;
<xsl:call-template name="Level3Check">
   <xsl:with-param name="type" select="'int'"/>
</xsl:call-template>   
<xsl:call-template name="Level3Check">
   <xsl:with-param name="type" select="'unsigned int'"/>
</xsl:call-template>
<xsl:call-template name="Level3Check">
   <xsl:with-param name="type" select="'short'"/>
</xsl:call-template>
<xsl:call-template name="Level3Check">
   <xsl:with-param name="type" select="'unsigned short'"/>
</xsl:call-template>
<xsl:call-template name="Level3Check">
   <xsl:with-param name="type" select="'char'"/>
</xsl:call-template>
<xsl:call-template name="Level3Check">
   <xsl:with-param name="type" select="'unsigned char'"/>
</xsl:call-template>
<xsl:call-template name="Level3Check">
   <xsl:with-param name="type" select="'bool'"/>
</xsl:call-template>
<xsl:call-template name="Level3Check">
   <xsl:with-param name="type" select="'float'"/>
</xsl:call-template>
<xsl:call-template name="Level3Check">
   <xsl:with-param name="type" select="'double'"/>
</xsl:call-template>
    }
   </xsl:if>
	setTestResult(TEST_SUCCESS,"Test Successful");
	return;
}
</xsl:document>
</xsl:template>


<!--================================================================-->
<!-- Utility to process a string made up of several words           -->
<!-- separated by a space and returning the same string with the    -->
<!-- same words with the first letter of each word capitalized.     -->
<!--================================================================-->

<xsl:template name="makeFirstLetterCap">
  <xsl:param name="before"/>
  <xsl:param name="after"/>
  <xsl:variable name="firstInitial" select="substring($after,1,1)"/>
  <xsl:variable name="restOfString" select="substring($after,2,string-length($after))"/>
  <xsl:variable name="firstLetterCap" select="translate(
          $firstInitial,'abcdefghijlmnopqrstuvywz','ABCDEFGHIJLMNOPQRSTUVYWZ')"/>
  <xsl:variable name="afterWithFirstCap" select="concat($firstLetterCap,$restOfString)"/>
  <xsl:choose>
    <xsl:when test="contains($afterWithFirstCap,' ')">
      <xsl:variable name="after_1" select="substring-before($afterWithFirstCap,' ')"/>
      <xsl:variable name="after_2" select="substring-after($afterWithFirstCap,' ')"/>
      <xsl:variable name="newBefore" select="concat($before,$after_1)"/>
      <xsl:call-template name="makeFirstLetterCap">
        <xsl:with-param name="before" select="$newBefore"/>
        <xsl:with-param name="after" select="$after_2"/>
      </xsl:call-template>
    </xsl:when>
    <xsl:otherwise>
      <xsl:value-of select="concat($before,$afterWithFirstCap)"/>
    </xsl:otherwise>
  </xsl:choose>

</xsl:template>

<!--================================================================-->
<!-- Utility to compute the lowest parId to which no database       -->
<!-- parameter is associated.                                       -->
<!-- If there are no gaps in the parameter identifiers, this        -->
<!-- template rule will return the value of the maximum parameter   -->
<!-- identifier + 1.                                                -->
<!-- When it is called the first time, the parameter 'current'      -->
<!-- should be set to one.                                          -->
<!--================================================================-->

<xsl:template name="computeLowestIllegalParId">
  <xsl:param name="current"/>
  <xsl:choose>
    <xsl:when test="//Parameter/Id[@value=$current]">
      <xsl:call-template name="computeLowestIllegalParId">
        <xsl:with-param name="current" select="$current+1"/>
      </xsl:call-template>
    </xsl:when>
    <xsl:otherwise>
      <xsl:value-of select="$current"/>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>

<!--================================================================-->
<!-- Utility to compute the maximum value of the parId field on     -->
<!-- all the Parameter elements.                                    -->
<!-- When it is called the first time, the parameter 'currentMax'   -->
<!-- should be set to zero and the parameter 'currentPos' should be -->
<!-- set to 1.                                                      -->
<!--================================================================-->

<xsl:template name="computeMaxParId">
  <xsl:param name="currentMax"/>
  <xsl:param name="currentPos"/>
  <xsl:choose>
    <xsl:when test="$currentPos=count(//Parameter)">
      <xsl:value-of select="$currentMax"/>
    </xsl:when>
    <xsl:otherwise>
      <xsl:variable name="valOfNextParId" select="//Parameter[$currentPos+1]/Id/@value"/>
      <xsl:choose>
        <xsl:when test="$currentMax &lt; $valOfNextParId">
          <xsl:call-template name="computeMaxParId">
            <xsl:with-param name="currentMax" select="$valOfNextParId"/>
            <xsl:with-param name="currentPos" select="$currentPos+1"/>
          </xsl:call-template>
        </xsl:when>
        <xsl:otherwise>
          <xsl:call-template name="computeMaxParId">
            <xsl:with-param name="currentMax" select="$currentMax"/>
            <xsl:with-param name="currentPos" select="$currentPos+1"/>
          </xsl:call-template>
        </xsl:otherwise>
      </xsl:choose>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>

<!--================================================================-->
<!-- Utility to write out a level 2-3 check.                        -->
<!-- The first template parameter is the name of the type of the    -->
<!-- database parameter. The second template parameter is the       -->
<!-- maximum value of the parameter identifier.                    -->
<!--================================================================-->

<xsl:template name="Level23Check">
  <xsl:param name="type"/>
  <xsl:param name="maxParId"/>
  <xsl:param name="illegalParId"/>
  <xsl:variable name="normalizedType">
      <xsl:call-template name="makeFirstLetterCap">
        <xsl:with-param name="before" select="''"/>
        <xsl:with-param name="after" select="$type"/>
      </xsl:call-template>
   </xsl:variable>
        pDB->setParameter(maxParId+1,(<xsl:value-of select="$type"/>)0);
        if ( !verifyLatestEvent(nEvt+1,EVT_ILLEGAL_DB_ACCESS) )
           return;
        nEvt++;  

        pDB->setParameter(illegalParId,(<xsl:value-of select="$type"/>)0);
        if ( !verifyLatestEvent(nEvt+1,EVT_ILLEGAL_DB_ACCESS) )
           return;
        nEvt++;  

        dummy_1 = (char*)pDB->getParameterPointer<xsl:value-of
            select="$normalizedType"/>(maxParId+1);
        if ( !verifyLatestEvent(nEvt+1,EVT_ILLEGAL_DB_ACCESS) )
            return;
        nEvt++; 

        dummy_1 = (char*)pDB->getParameterPointer<xsl:value-of
            select="$normalizedType"/>(illegalParId);
        if ( !verifyLatestEvent(nEvt+1,EVT_ILLEGAL_DB_ACCESS) )
            return;
        nEvt++; <xsl:text/>        
</xsl:template>

<!--================================================================-->
<!-- Utility to write out a level 3 check.                          -->
<!-- The first template parameter is the name of the type of the    -->
<!-- database parameter. The second template parameter is the       -->
<!-- maximum value of the parameter identifier.                    -->
<!--================================================================-->

<xsl:template name="Level3Check">
  <xsl:param name="type"/>
  <xsl:variable name="normalizedType">
      <xsl:call-template name="makeFirstLetterCap">
        <xsl:with-param name="before" select="''"/>
        <xsl:with-param name="after" select="$type"/>
      </xsl:call-template>
   </xsl:variable>
        dummy_2 = (double)pDB->getParameter<xsl:value-of select="$normalizedType"/>(maxParId+1);
        if ( !verifyLatestEvent(nEvt+1,EVT_ILLEGAL_DB_ACCESS) )
            return;
        nEvt++;  

        dummy_2 = (double)pDB->getParameter<xsl:value-of select="$normalizedType"/>(illegalParId);
        if ( !verifyLatestEvent(nEvt+1,EVT_ILLEGAL_DB_ACCESS) )
            return;
        nEvt++;  
</xsl:template>


</xsl:stylesheet>

