IBM
Contents Index Previous Next



Example of TTCN Access Usability


To visualize the strength of TTCN Access, this section will discuss a small TTCN Access application. The example is a generic encoder.

The Encoder

Transforming an abstract test suite into an executable test suite will eventually involve the problem of representing the actual ASP and PDU signals as bit patterns. The step from abstract syntax (TTCN) to transfer syntax (bit patterns) has to be provided and implemented by someone with vast knowledge of the actual protocol as well as the test system and the test environment.

The encoder described in this small example will assume the following:

These assumptions tell us that encoding functions are data driven and that the encoding function has to be derived from the type definitions. It also tells us that the encoding of base types, that is INTEGER, BOOLEAN, etc., are identical.

Before looking at the algorithm for the generic encoder, let us have a look at a specific type and how the corresponding encoding function may be implemented. The type will be a small PDU as below:

Figure 180 : TTCN PDU type definition

The corresponding encoding function may look like:

void AUTHENT_REQ1_encode( AUTHENT_REQ1* me, char* enc_buf )
{
  INTEGER_encode( &me->message_flag, enc_buf );
  BITSTRING_encode( &me->message_type, enc_buf );
  AUTH_TYPE_encode( &me->auth_type, enc_buf );
}

It is a data driven encoding function that given any element of type AUTHENT_REQ1 will encode them all identical. The first argument is a pointer to the element that shall be encoded, the second argument is the buffer where the result of the encoding shall be stored.

The function may of course contain more code and more information, but for this example, the above is the smallest encoder function needed.

The following example will give an algorithm for how the encode functions may be generated via TTCN Access. The algorithm is followed by a small TTCN Access application generating the actual encoder.

FUNCTION GenerateEncoder( type : typedefinition )
BEGIN
/* Generate encoder function header such as: */
/* void type_encode( type* me, char* enc_buf ) */
/* { */
FOR( "every element in the structured type" )
/* Generate a call to the element type encoder 
/* function
/* such as: */
/* element_type_encode( &type->element, enc_buf );
END
/* Generate encoder function footer such as: */
/* } */
END

The above algorithm will generate generic encoders for any type. Of course, header files and base type encoder functions must be provided/generated as well. Below is a nearly complete TTCN Access application that generates encoders for any TTCN PDU type definition. Observe how the visitor class is customized to traverse and generate side effects for the specific parts we are interested in.


// Start by customizing the default visitor class

class Trav : public AccessVisitor
{
public:
  void VisitTTCN_PDU_TypeDef( const TTCN_PDU_TypeDef& Me );
  void VisitPDU_FieldDcl( const PDU_FieldDcl& Me );
};

void Trav::VisitTTCN_PDU_TypeDef( const TTCN_PDU_TypeDef& Me )
{
  // Generate the header part

  cout << Me.pdu_Identifier( ) << "_encode( const ";
  cout << Me.pdu_Identifier( ) << "& me, char* enc_buf )";
  cout << "\n{" << endl;

  // Traverse fields using default traverser

  AccessVisitor::VisitPDU_FieldDcls( Me.pdu_FieldDcls( ) );

  // Generate the footer part

  cout << "}" << endl;
}

void Trav::VisitPDU_FieldDcl( const PDU_FieldDcl& Me )
{
  Astring type = get_type( Me.pdu_FieldType( ) );
  Astring name = get_name( Me.pdu_FieldId( ) );
  
  cout << "void " << type << "_encode( me->"
       << name << "( ), enc_buf );" << endl;
}

All that remains now is a main function for the generic encode generator.

#include     <stdio.h>
#include     <iostream.h>
#include     <time.h>
#include     <ITEXAccessClasses.hh>
#include     <ITEXAccessVisitor.hh>

class Trav : public AccessVisitor
{
public:
  void VisitTTCN_PDU_TypeDef( const TTCN_PDU_TypeDef& Me );
  void VisitPDU_FieldDcl( const PDU_FieldDcl& Me );
};

int main( int argc, char **argv )
{
  //The actual suite
  
  AccessSuite suite;
  
  if ( argc != 2 )
    {
      fprintf( stderr, "usage: %s suitename\n", argv[ 0 ] );
      return 0;
    }

  /* Open the suite and go for it! */
  
  if ( suite.open( argv[ 1 ] ) )
    {
      Trav trav;
      
      trav.Visit( suite );
      suite.close( );
    }
}

The get_type and get_name functions can be simple or complex. See the example below:

Astring get_type( const PDU_FieldType& Me )
{
  TypeAndAttributes ta = Me.typeAndAttributes( );
  switch ( ta.choice( ) )
    {
    case Choices::c_TypeAndLengthAttribute:
      return get_type( ta.typeAndLengthAttribute( ) );
    default:
      cerr << "ERROR: Type not supported: " 
<< Me.content( ) << endl;
      return "***#***";
    }
}


Astring get_type( const TypeAndLengthAttribute& Me )
{
  const TTCN_Type tt = Me.ttcn_Type( );

  switch ( tt.choice( ) )
    {
    case Choices::c_PredefinedType:
      if ( tt.predefinedType( ).choice( ) ==
Choices::c_INTEGER )
        	 return "INTEGER";
      break;
    case Choices::c_ReferenceType:
      return tt.referenceType( ).identifier( );
    default:
      break;
    }
  cerr << "ERROR: Type not supported: " 
<< Me.content( ) << endl;
  return "***#***";
}

    
Astring get_name( const PDU_FieldId& Me )
{
  const PDU_FieldIdOrMacro pfid = Me.pdu_FieldIdOrMacro( );
  if ( pfid.choice( ) != Choices::c_PDU_FieldIdAndFullId )
    {
      cerr << "ERROR: Slot name not supported: " 
<< Me.content( ) << endl;
      return "***#***";
    }

  return pfid->pdu_FieldIdAndFullId( ).pdu_FieldIdentifier( );
}

http://www.ibm.com/rational
Contents Index Previous Next