IBM
Contents Index Previous Next



Examples


This section provides all the examples in this chapter. It starts with a simple TTCN Access application and continues from there. Every example is discussed in its own subsection. In each subsection, only the interesting parts are discussed. A complete solution to every example can be found in Solutions to the Examples.

Every TTCN Access application can be seen as an application providing a solution to a problem. These problems are related to TTCN test suites in general, such as reporters or style checkers, encoders and decoders. Therefore, every example in this chapter will be preceded with a small discussion of the actual problem that the corresponding TTCN Access application shall solve. Of course, the problems discussed in this chapter will mainly be of a fictive nature, but they will reflect the simplicity of TTCN Access and the different implementation techniques and methods that TTCN Access provides.

In all examples, we assume that there exist a global instance of the class AccessSuite called suite, a global instance of the class AccessVisitor called visitor and that a test suite has been opened.

The Identifiers

Objective

In every test suite there exists a set of identifiers. The objective of this example is to print out every identifier present in the test suite.

Solution 1

Every identifier present in an Access tree will be represented as an Access node of type Identifier. The solution will therefore only include one user defined method in the visitor class instance that, when entering the node Identifier, prints the content of that class. In this case it is the name of the identifier. The method is provided below.

void Trav::VisitIdentifier( const Identifier& Me )
{
  printf( "Identifier %s\n", (const char*) Me );
}

This method will be called from TTCN Access every time the traverser enters the Identifier node. The name Identifier is the name of the Access node and the prefix tag Visit means that this is a visiting method.

As the task of a TTCN Access application is to traverse a test suite according to the traverser and call possibly user defined functions or methods, we need to create a traverser that will use the default traversing, but have the desired small change. This is done by sub classing as follows:

class Trav : public AccessVisitor
{
public:
  void VisitIdentifier( const Identifier& id );
};

As identifiers are present everywhere in the Access tree, no change to the traversing order needs to be done. The default traverser will be used and the traversing will start from root.

The full solution is found in Solution 1.

Context

Objective

When executing the previous example, all identifiers in the given test suite will be printed. By looking at the output one might think that there should not be so many identifiers in the test suite, but the way in which the grammars are specified (both TTCN and ASN.1), nearly every grammar rule ends in a identifier. This example will explain the importance of calling the user defined function at their correct place, or to be more specific, in its right context.

Let us assume, with the previous example in mind, that we want to distinguish between TTCN PDU type definition identifiers and TTCN PDU constraint identifiers (the rest is of no concern). This can be achieved in several different ways. Below are two different solutions to this problem.

Solution 2

This first solution, looking at each identifiers type, will be implemented in the visiting method used in the previous example. However, it has to be extended to look at each identifier type and only print the appropriate ones. The updated method is found below.

void Trav::VisitIdentifier( const Identifier& Me )
{
  switch( Me.choice( ) ) 
    {
      case Choices::c_TTCN_PDU:
        printf( "Identifier `%s' is a TTCN PDU type\n",
                (const char*) Me );
        break;

      case Choices::c_TTCN_PDU_Cons:
        printf( "Identifier `%s' is a TTCN PDU constraint\n",
                (const char*) Me );
        break;

      default:
        break;
    }
}

Solution 3

The second solution will replace the used method with two new ones. The first method will print out every TTCN PDU type definition identifier. This will be done in the method VisitTTCN_PDU_TypeDef. The second, VisitTTCN_PDU_Constraint, will print out every TTCN PDU constraint identifier. In each method the Identifier Access node is reached by explicit addressing, that is, explicitly naming the path to the Access node Identifier. Their corresponding definitions are supplied below.

 void Trav::VisitTTCN_PDU_TypeDef( const TTCN_PDU_TypeDef& Me )
{
  printf( "Identifier `%s' is a TTCN PDU type\n",
           (const char*) Me.pdu_Id( ).pdu_IdAndFullId( )
           .pdu_Identifier( ) );
}

void Trav::VisitTTCN_PDU_Constraint( const 
TTCN_PDU_Constraint& Me)
{
  printf( "Identifier `%s' is a TTCN PDU constraint\n",
          (const char*) Me.consId( ).consIdAndParList( ).
          .constraintIdentifier( ) );
}

The definition of the visitor object is done as follows:

class Trav : public AccessVisitor
{
public:
  void VisitTTCN_PDU_TypeDef( const 
TTCN_PDU_TypeDef& );	 
  void VisitTTCN_PDU_Constraint( const 
TTCN_PDU_Constraint& );
};

Comments

When executing the two examples above with the test suite in the end of this chapter as input, one will find that the output is not equivalent. The first solution will have some more output lines that the second one. By adding the following line to each method, one will detect in which table the identifier was found.

printf( "In table `%s': ", (const char*) Me.table_name() );

One will find that the extra lines of output in the first solution are produced from the Constraints Part and the Dynamic Part. This is true due to the fact that the type identifiers are being used in each constraint and the constraint identifiers are being used in the Constraint Reference column in each test case and test step table.

The full solutions are found in Solution 2 and Solution 3.

Translating TTCN

A very common and useful TTCN Access application is to translate a test suite to another target language. Examples are C, C++, Pascal etc. By doing this translation we can thereby create an executable test suite. To achieve this, one needs a TTCN translator that translates a TTCN test suite to the specific source code. This example will not be a full translator, but will rather show how such a translator can be written by using TTCN Access.

Objective

In this example, we will translate TTCN PDU type definitions to C where each PDU will be a unique C type. To achieve this, we need to have some kind of mapping between TTCN and C. One way to do this is to do a case study. First we will look at a TTCN PDU type definition in the table format and from that table extract how the corresponding C representation shall be. Then, a generic representation of all TTCN PDUs in C will be defined. This generic representation will then be implemented in TTCN Access, and thereby a generic TTCN PDU type definition to C translator will be implemented.

Solution 4

Let us have a look at a TTCN PDU type definition in table format. The table below, the TTCN PDU type definition SEND, is taken from the test suite attached to the end of this chapter.

Figure 182 : TTCN PDU Type Definition

A corresponding C representation of the above type could look something like:

typedef struct {
 INTEGER Field_1;
 BOOLEAN Field_2;
} SEND;

That is, a structured type holding the same number of elements as the corresponding TTCN type definition. In this example, no consideration is taken to the PCO type. This is only done for simplicity and can of course be included in the type as well.

As one can see in this example there are a lot similarities between the TTCN definition and the C representation in terms of names of elements and their corresponding type. This helps us define a generic C representation of a TTCN PDU type definition as below:

typedef struct {
 Element1_Type Element1_Name;
 Element2_Type Element2_Name;
 ...
 ElementN_Type ElementN_Name;
} PDU_TypeName;

The type and name of each element is taken from the corresponding names in the TTCN type definition and the type defined is named as in TTCN.

Now, the next step is to implement this generic type in TTCN Access! To do this, we divide the generic C type into three distinct elements; the header, the body and the footer.

The Header and Footer

The visitor method that traverses the TTCN PDU type definitions, will be the one responsible for generating the header and footer of the generated C structure definition. The method may look something like this:

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

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

  // Traverse fields using default traverser

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

  // Generate the footer part

  cout << "}" << endl;
}

This method will be called every time the traverser enters the Access node TTCN_PDU_TypeDef.

The Body

The body of the type definition, is a collection of rows where each row is translated identically. A row can be translated by defining the following method:

void Trav::VisitPDU_FieldDcl( const PDU_FieldDcl& Me )
{
  printf( "  %s %s;\n", 
          (const char*) get_type_str( Me.pdu_FieldType( ), 
          (const char*) get_id( Me.pdu_FieldId( ) );
}

where get_type_str and get_id are two functions returning the type and the name of the element respectively. This method shall be called every time the traverser enters the Access node PDU_FieldDcl.

The full solution is found in Solution 4.


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