wiki:Documentation/T3Q

Version 2 (modified by phdmakk, 7 years ago) (diff)

--

T3Q Documentation

T3Q Documentation Outline

  1. Installation / Setup
  2. Using T3Q
    1. Configuration
    2. Command-Line Usage
    3. Output Format
    4. Performance and Memory Usage
  3. T3Q Quality Checks
    1. Naming Conventions
    1. Structure of Data
      1. Alphabetic Ordering of Types withing Groups
      2. Grouping of Ports and Related Messages
      3. No All Keyword in Port Type Definitions
    1. Log Statements
      1. Log Format Must Match the Format of a Regular Expression
      2. External Function Invocation Must Be Preceded By A Log Statement
      3. Inconclusive or Fail Setverdict Statement Must be Preceded by a Log …
    1. Code Style
      1. There Must Be No Labels or Goto Statements
      2. There Must Be No Nested Alt Statements
      3. There Must Be No Permutation Keyword
      4. There Must Be No AnyType Keyword
      5. There Must Be No Modified Template of a Modified Template
      6. Local Definitions Must Be Declared at the Beginning of Testcases, …
      7. Import Statements Must Be Declared at the Beginning of Modules
      8. There Must Be No Duplicated Identifiers On the Module Level
      9. There Must Be No Unused Definitions On the Module Level
      10. There Must Be No Inline Templates
      11. There Must Be No Over-specific Runs On Clauses
      12. There Must Be No Unused Imports
      13. There Must Be No Unused Formal Parameters
      14. There Must Be No Unused Local Definitions
      15. There Must Be No Uninitialised Local Variables
      16. There Must Be No Literals
    1. Test Suite Modularization: Module Containment
      1. TypesAndValues Module Must Contain Only Type and Constant Definitions
      2. Templates Module Must Contain Only Template Definitions
      3. Functions Module Must Contain Only Function and Altstep Definitions
      4. Testcases Module Must Contain Only Testcase and Function Definitions That …
      5. ModuleParams Module Must Contain Only Modulepar Definitions
      6. Interface Module Must Contain Only Component, Port, and Type Definitions
      7. TestSystem Module Must Contain Only Component and Port Definitions
      8. TestControl Module Must Contain Only Control Part Definition
    1. Test Suite Modularization: Importing Libraries
      1. TypesAndValues Modules Must Always Import From Certain Modules
      2. Testcases Module Must Always Import From Modules Prefixes with …
    1. Module Size
  4. T3Q Code Formatting Feature
  5. T3Q Misc Features
    1. List Imported Module Names
    2. List Imported File Names
    3. List Importing Module Names
    4. List Importing File Names

T3Q is a quality checking and code formatting tool for TTCN-3. It analyzes TTCN-3 source code for a defined set of anomalies that affect the quality of the code. In addition, it presents an option to automatically format (beautify, pretty-print) the source code according to a number of settings.

Installation / Setup

The following software must be installed on the system prior to the use of T3Q

  • A Java Runtime, at least version 1.7 (http://java.sun.com, will be installed automatically during T3Q installation if not already present).

The T3Q command-line tool requires two environment variables to be set no matter what the operating system is.

  • JAVA_HOME - should point to the Java Runtime
  • T3Q_HOME - should point to the installation directory of T3Q

The installation tool for Windows should take care of setting these environment variables correctly including the installation of Java if necessary. For Unix environments, these have to be configured manually (we will refer to MacOS as Unix environment as well). In order to use T3Q properly, we suggest to include T3Q_HOME in the path variable of your Unix system. The Windows Installer automatically takes care of the inclusion in the system path.

Using T3Q

T3Q is a command line tool which can be called by simply typing "t3q" in Windows or on Unix systems. The Windows command-line can be accessed by starting the program "cmd". For Unix systems, we only support bash environments.

Configuration

T3Q uses an XML-based configuration format. Starting with version v0.4.2, the location of the configuration file must be supplied as a command line option during execution (the location was previously based in the default user's data location - depending on the system, a file t3q.xml was stored in %APPDATA%\T3Q (Windows) or in ~/.t3q/ (Unix)). The location of the %APPDATA% directory depended on the username, the Windows version and possibly the localization. For example, for a user 'foobar' on a German Windows XP machine, the resulting configuration path would be C:\Documents and Settings\foobar\Application Data\T3Q. In version v0.4.2 and onwards, the location of the configuration file has to be supplied every time T3Q is called. Additionally, starting with version v1.0.1, if there is no existing configuration file in the selected location, the tool will prompt the user to use the appropriate option to generate a new configuration with the default settings. Thus, the tool has to be started with the appropriate parameter to generate a new configuration prior to actual usage. This way, it will be possible to modify the configuration file to accommodate the particular needs of the user prior to performing any analysis. By location here the path, filename, and extension of the configuration file are meant, which implies that any filename and any extension can be used. It is probably best to retain certain norms in naming the configuration files, at least in preserving the file extensions (.xml) to avoid confusion.

Please note that after an update, during the development stage, the configuration files will often be extended. Thus, it may be necessary to generate a new configuration file and transfer the custom settings from the old configuration file. The configuration file has two sections:

  • A configuration profiles section
  • A main section

The ConfigurationProfiles section contains a list of QualityCheckProfile elements. Its elements contain the tags profilename as well as check* elements and other specific elements that are needed for the configuration of some of the quality checks. In the default t3q.xml that is created, there is a profile called defaultProfile that initializes all profile configuration values to the default values and enables all checks. This is also the configuration of an implicitly given profile called all. The all profile is not part of the XML configuration, but it exists and is known to the tool.

Since v0.3.1, configuration profiles also have a version (profileVersion element), that regulates the profile compatibility. If a profile from an older version is used, T3Q will throw and error and recommend profile upgrade or the selection of another profile. Also, further robustness checks have been introduced to provide hints if the configuration profile is otherwise incompatible or corrupted. In case of a problem that can be localized, a corresponding error message is provided suggesting the location of the problem.

Also, there are several generic options, that affect the overall behavior of the T3Q tool. The known extensions for files that are to be processed can be specified by means of a regular expression in the resourceExtensionsRegExp option. By default, ttcn,ttcn3 and 3mp file extensions are recognized. Since v1.0.1, there is also support for supplying input by means of what will be referred to as project files. These files specify a list of input files and directories (including wildcards). The projectExtension option regulates what is to be considered a project file. Note that this is not a regular expression option, therefore only a single value is currently supported. Since v1.0.3, the ignoredResourceRegExp option enables the specification of regular expressions for resources within the set of input files that will be ignored during the processing steps. Note that all resources in the input set will be parsed and pre-processed so that definitions within ignored resources will be still be correctly resolved during the analysis phase. The ignored resources will be skipped during the analysis and formatting steps (annotated with (Skipped) in the output during analysis and formatting). The default setting for ignored resources is .*IGNORED.*, meaning that resources which contain IGNORED in their full path will be skipped. There is an option to switch recursive processing on and off (settingRecursiveProcessing). There is an option to switch aborting on (parsing) errors on and off (settingAbortOnError). Both of these options are turned on by default. Turning them off may result in unreliable output. Files that contain syntax errors will be analyzed only up to the point of the first syntax error occurrence. As a result, imported definitions may not be resolved correctly, which in turn may affect some of the quality checks. The same situation may occur if not all the resources in a test suite are processed.

Additionally, there are options to regulate the output. As as of version 0.4.1, these are grouped under loggingConfiguration. statShowFullPath can be used to enable / disable the display of the path of a file in the output, when a quality check is violated. Additionally, if desired, statShowFilename can be set to false to disable outputting the filename with each output message. Further options include showMessageClass - to display the message class (or also quality check class, e.g. naming convention, code style, etc), showDetails - to display further details about the output message, which in the current state generally shows the internal name of the quality check that generated the message (the internal name is generally corresponding to the configuration entry for easy traceability), and the reference requirement ID (although the latter may be omitted in subsequent releases). There is also an option logOutputPrefix to add a custom prefix to every log message (at the beginning of the line, before the path / filename). By default, this option adds three empty spaces before each logging message in the output.

There are two further settings related to the output - one that shows a brief statistics summary with basically counters of the occurrences of each message class (statShowSummary) and one that enables / disables output statistics about the length of the files being analyzed (in lines of code) - statShowLOC.

In the main section, there is currently one single configuration element defaultConfigurationProfile. It points to the implicit all profile by default. The defaultConfigurationProfile is the profile that will be used if no specific profile is provided as command-line parameter. If the specified defaultConfigurationProfile does not exist in the configuration, T3Q will fall back on the implicit all profile.

Command-Line Usage

T3Q is used as follows:

t3q [options] ( path | filename )+

This means that apart from any required options (see below), there always has to be at very least one parameter that needs to be specified. This parameter is the input parameter, which can be either a path that contains the TTCN-3 files that should be analyzed, the name of an individual file, or any combination of these (a mixed list), including wildcards.

  • If a path provided as input (and recursive processing is enabled in the configuration, which is the default setting), T3Q will recursively parse and analyze all files in this directory that match the provided file extensions (which are specified in the configuration file). For the current path a simple '.' is sufficient. If no files match these extensions, T3Q will output a corresponding message and quit.
  • If an individual file is provided as input, then only that file will be processed.
  • If the path or filename contains spaces, you need to put the path into quotation marks or use the auto-completion feature of the environment (provided there is one), which should take care of escaping spaces or enclosing the complete path in quotation marks.
  • If a list of individual files and/or paths are provided as input, these will be combined and processed together.
  • If wildcards are used, these will be expanded by the command-line environment into a list and subsequently analyzed as such.

The following options can be provided currently and can be specified in any order:

    --generate-config <FILE NAME>   Generate a new default configuration
                                    file at the specified location
    --config <FILE NAME>            Configuration file location
    --profile <PROFILE NAME>        Configuration profile

    --format                        Apply code formatting
    --verbosity <LOG LEVEL>         Verbosity level (currently supports ERROR,
                                    WARNING and INFORMATION values)

    --local-dependencies            Generate local dependencies

    --output-path <PATH>            Destination path for the output (if 
                                    applicable, otherwise ignored). 
                                    Overrides the profile setting. 
    --help                          Show this usage information screen

  • --help will provide brief usage information listing the expected syntax and the available options. T3Q will stop and analyze no files when the help screen is called.
  • The --generate-config option (new as of v1.0.1) allows the generation of new default configuration files at the location specified. T3Q will then quit.
  • The --config option (new as of v0.4.2) is mandatory and has to be specified every time T3Q is run (except when --help or --generate-config are used). It specifies the location of the configuration file. Starting with v1.0.1, if no configuration file is found at the specified location, the user will be prompted to use the appropriate option (--generate-config) to produce a new default configuration. To use the default location from previous versions one will have to specify it manually, e.g.
    t3q --config ~/.t3q/t3q.xml 
    
    on a UNIX based system or
    t3q --config %APPDATA%\T3Q}\t3q.xml 
    
    on a Windows based system. The --generate-config and the --config options are mutually exclusive, with --generate-config having precedence, meaning that if both are specified, T3Q will still only generate the new default configuration and quit. Please not that if the location of the configuration file contains spaces, it has to be either enclosed in quotation marks or the auto-completion feature of the environment has to be used to take care of escaping the spaces.
  • The --profile option overrides the defaultConfigurationProfile in the XML configuration. This means that you can specify multiple profiles in the XML configuration and run T3Q using another existing profile without the need to change the XML configuration. If the profile specified on the command-line does not exist, T3Q will automatically fall back to the default profile provided in the main section of XML configuration. In turn, if this default profile does not exist as well, T3Q will fall back to the implicit all profile. If the configuration profile name contains any empty spaces, they need to be escaped or the profile name needs to be enclosed in quotation marks, depending on the environment.
  • The --format option (newly introduced in v0.4.2) enables the code formatting feature (see below), which had to be enabled by a configuration entry in the configuration profile in previous versions. That configuration entry is now superseded by the command line option, although the output path where the formatted output is to be placed still needs to be specified in the configuration profile (this may also be superseded by a command line argument for convenience in future releases).
  • The --verbosity option (also newly introduced in v0.4.2) regulates the verbosity level of the output messages based on their type. The possible values are ERROR, WARNING and INFORMATION (in an ascending inclusive order, meaning that when INFORMATION is selected, the output will include both ERROR and WARNING verbosity level messages as well). INFORMATION is the default setting. More information about the message types is available in the next section.
  • The --local-dependencies option (newly introduced in v2.0.0b23) enables the generation of local-dependencies. Currently, when the feature is activated, the other checks are deactivated. The location of the generated output can be specified with the dependencyOutputPath in the configuration profile (DOCUMENTATION by default). The output path can also be overridden by the command line argument for the --output-path option.
  • The --output-path option (newly introduced in v1.0.1) makes it possible to supply the output path at the command line interface (overriding the profile setting). If affects only the code formatting feature and if it is not used, this optionr is simply ignored. It is added purely for convenience in case the same profile has to be used on different projects with different destination paths.

The native binary executable for Windows supplied with v1.0.1 is discarded again as of v1.0.2, due to the fact that it does not grant the desired advantages. Thus, the basic usage is reverted to the batch scripts. Starting with v1.0.2, the batch scripts include a "hidden" --echo option, which simply outputs the deployment specific call to the Java virtual machine, without any command line arguments, meaning that it makes no sense to provide any further command line parameters besides the --echo option. The sole purpose of this option is to output the full command line necessary for starting the tool, which may be necessary for embedding into third party tools. This is why this option is considered hidden (it also does not show in the standard help screen). It should not affect the general usage of the tool. If, for whatever reason, other command line arguments are supplied together with the --echo option, then the --echo option needs to be the first command line argument.

Output Format

The output format is configurable to a certain degree. Individual files being analyzed are listed, and if any of the quality checks are violated an output message is provided. The message format is:

[Prefix][[Path]FileName: ]LineNumber: MessageType: [MessageClass: ]Message[ (MessageDetails)]

where whether the path is displayed can be switched on or off in the T3Q configuration using the statShowFullPath boolean switch. If statShowFullPath is turned off, only the filename is displayed, otherwise the path is displayed as supplied to T3Q, including the subdirectories. The filename provides the name of the file where the violation occurred. It is also optional. Whether the filename is displayed or not is determined by the statShowFilename boolean switch. It can be handy to reduce output clutter because all the output messages are grouped under the files they occurred in anyway. The line number(s) indicates the line or scope of lines (separated by "-") where the violation occurred. The message type indicates the type of message. There are currently three types of messages WARNING - if a quality check is violated, INFORMATION in case a processing problem has occurred, and ERROR in case a serious error (such as a parsing error) has occurred (note that currently parsing errors may have a different format, they are in the process of being unified in format with the other message types). After the message type, if enabled (via the showMessageClass switch), the message class will show information about the type of quality check violated. There have been seven message classes initially defined:

  • General - for general messages
  • Naming Conventions - for naming conventions-related violations and messages
  • Code Documentation - for documentation-related violations and messages
  • Log Statements - for violations and messages related to log statements
  • Structure of Data - for violations and messages related to the structure of data
  • Code Style - for violations and messages related to coding style
  • Test Suite Modularization - for violations and messages related to modularization

In addition there is also the Universal class, for messages that do not fall into any of the other categories. These message classes are also used for the brief statistics summary at the end of the processing (if enabled). These classes can be used for further filtering of the output. The improved logging interface will allow the generation of structured file format log (such as XML), which may subsequently be used with other tools for automated processing, filtering, and sorting based on any of the output fields.

The message contains the details about the occurrence. Finally, the optional message details contain further details about the occurrence, which in the general case amount to a reference to the internal name of the quality constraint being violated, which is identical to the configuration tag.

Examlpes:

with path:

ETSI 3GPP/IWD_09wk04/7_1/MAC.ttcn: 2107-2117: WARNING: Code Style: A nested 
alt statement is used! (6.3, checkNoNestedAltStatements)

without path, class, and details:

MAC.ttcn: 2107-2117: WARNING: A nested alt statement is used!

Performance and Memory Usage

Large TTCN-3 test suites tend to take quite a while to process (both for parsing and for analysis). Therefore, it is generally a good idea to set larger memory limits (as far as the system allows) in order to improve processing time and avoid possible memory problems. The default setting is to set the upper memory limit to 512MB, which by today's standards is rather conservative, however, it should be sufficient for smaller to medium-sized TTCN-3 test suites. The optimal memory limits are not easy to determine, and ways to automatically calculate and set these depending on the available system resources, the size of the input TTCN-3 test suite, and the configuration in use are currently being investigated. In the meantime, should processing take too long or memory errors occur, it is advisable to set a higher upper memory limit, depending on the available system resources. This can be done by manually editing the parameters in the start scripts (t3q.bat and t3q for Windows and Unix respectively). These files should be edited very carefully, as mistakes may prevent T3Q from starting. Under Windows, in t3q.bat, set the -Xmx parameter in following line:

set JAVA_CMD=%JAVA% -Xmx512m -Xss128m -cp "%CLASSPATH%" org.etsi.t3q.T3Q 

to the desired upper limit (e.g. to -Xmx1024m for a 1GB upper memory limit).

Under Unix, the t3q file can be changed in a similar fashion by setting the -Xmx parameter in the

JAVA_CMD="$JAVA -Xmx512m -Xss128m -cp $CLASSPATH org.etsi.t3q.T3Q"

line to the desired upper limit.

In general, the optimal setting depends on the size of the TTCN-3 test suite and to a degree on the selected quality checks.

As of v1.0.3, a tool to guesstimate the optimal memory settings is included with T3Q. This tool is launched prior to the actual tool execution and attempts to detect the maximum memory settings with which T3Q can be started at that particular moment, aiming to both reduce processing time and avoid potential out of memory errors. It should be noted that this tool can be considered in beta status, as in some edge cases it may cause T3Q to crash or to fail at start. Such cases should be reported so that the memory detection tool can be further adjusted to avoid such issues in the future. It is still possible to select preferred memory settings manually by adjusting the start-up scripts as described above, where the particular line has been changed to:

set JAVA_CMD=%JAVA% -Xmx%HEAP%m -Xss128m -cp "%CLASSPATH%" org.etsi.t3q.T3Q

under Windows and to

JAVA_CMD="$JAVA -Xmx`$MT_CMD`m -Xss128m -cp $CLASSPATH org.etsi.t3q.T3Q"

under Unix, and the %HEAP% and `$MT_CMD` parts of the line should be substituted with the desired settings.

T3Q Quality Checks

In the following, we describe the checks that T3Q is currently able to do. We describe them by their natural name in the section heading and with their symbolic name that is used to configure them in the configuration profile. Also we will refer to dependent tags in the configuration profile. Please note that the provided example are not semantically complete. They are just used to illustrate the problems. We provide sample listings where appropriate to illustrate the checks further.

Naming Conventions

  • Symbolic Name in XML Configuration: checkNamingConventions
  • Dependant Tags in XML Configuration: namingConventionsConfig (the whole subsection)

This quality check analyzes the identifiers for different entities (also in different contexts) and checks whether they comply to the supplied naming schemes. The naming schemes are defined as regular expressions in the "namingConventionsConfig" subsection in the T3Q configuration file. The basis for the naming conventions as well as the default values are taken from http://www.ttcn-3.org/NamingConventions.htm. The default settings in the "namingConventionsConfig" subsection are listed below. The fields are self-explanatory - they are formed following the schema "{languageElement}RegExp", where the language elements are also taken from http://www.ttcn-3.org/NamingConventions.htm and ordered in the same way as on the web page. Blank naming rules will be ignored.

      <namingConventionsConfig>
        <moduleRegExp>[A-Z].*</moduleRegExp>
        <groupRegExp>[a-z].*</groupRegExp>
        <dataTypeRegExp>[A-Z].*</dataTypeRegExp>
        <messageTemplateRegExp>m_[a-z].*</messageTemplateRegExp>
        <messageTemplateWithWildcardsRegExp>mw_[a-z].*</messageTemplateWithWildcardsRegExp>
        <derivedMessageTemplateRegExp>md_[a-z].*</derivedMessageTemplateRegExp>
        <derivedMessageTemplateWithWildcardsRegExp>mdw_[a-z].*</derivedMessageTemplateWithWildcardsRegExp>
        <stf160sendTemplateRegExp>cs_[a-z].*</stf160sendTemplateRegExp>
        <stf160receiveTemplateRegExp>cr_[a-z].*</stf160receiveTemplateRegExp>
        <signatureTemplateRegExp>s_[a-z].*</signatureTemplateRegExp>
        <portInstanceRegExp>[a-z].*</portInstanceRegExp>
        <componentInstanceRegExp>[a-z].*</componentInstanceRegExp>
        <constantRegExp>c_[a-z].*</constantRegExp>
        <localConstantRegExp>cl_[a-z].*</localConstantRegExp>
        <extConstantRegExp>cx_[a-z].*</extConstantRegExp>
        <functionRegExp>f_[a-z].*</functionRegExp>
        <extFunctionRegExp>fx_[a-z].*</extFunctionRegExp>
        <altstepRegExp>a_[a-z].*</altstepRegExp>
        <testcaseRegExp>TC_.*</testcaseRegExp>
        <variableRegExp>v_[a-z].*</variableRegExp>
        <componentVariableRegExp>vc_[a-z].*</componentVariableRegExp>
        <timerRegExp>t_[a-z].*</timerRegExp>
        <componentTimerRegExp>tc_[a-z].*</componentTimerRegExp>
        <moduleParameterRegExp>[A-Z][A-Z_1-9]*</moduleParameterRegExp>
        <formalParameterRegExp>p_[a-z].*</formalParameterRegExp>
        <enumeratedValueRegExp>e_[a-z].*</enumeratedValueRegExp>
      </namingConventionsConfig>

Note that component and port type definitions fall under the generic category "data type" definitions and are therefore required to follow the same naming schema (start with an uppercase letter). This may be subject to changes in the future. Note also that variables in "for" statements are also required to follow the general naming convention for all variables. Additionally, note that only message templates that directly include wildcards or matching expressions are classified as "message templates with wildcards / matching expressions". This will be subject to change in the future, in that a deep search will be performed, resolving all referenced templates and probing them for wildcards / matching expressions.

Note also that there are additional template restriction based naming conventions checks for templates. These reflect the STF160's notions of send and receive templates. Although the names may sound misleading, for these naming conventions the actual usage context (i.e. send or receive statements) for the templates in question is not taken into consideration. These rules are based on template restrictions in the definition of the templates, thus are also content-based. The rules according to which templates are classified as send or receive templates are as follows:

  1. Templates defined with an omit or value restriction are considered send templates and shall conform to the naming convention. If such templates have formal template parameters, then these formal template parameters shall also be defined with the same (omit or value) template restrictions. If the formal template parameters are not defined with the appropriate template restrictions for this type of template (i.e. the template definition is defined inconsistently or ambiguously), an INFORMATION message will be provided informing of the occurrence, and the naming convention will not be checked for such occurrences.
  2. Templates defined without a restriction or with a present restriction are considered receive templates and shall conform to the naming convention. There is no restriction on the formal template parameters for such templates.

With careful selection of the naming conventions rules, it is possible to combine the template naming conventions for wildcards / no wildcards and STF160's send / receive templates if desired. If only STF160's send / receive distinction is desired, then the naming convention rules for wildcards / no wildcards templates shall be left blank.

Structure of Data

Alphabetic Ordering of Types withing Groups

  • Symbolic Name in XML Configuration: checkTypeDefOrderInGroup
  • Dependant Tags in XML Configuration: -

This quality check analyzes type definitions within groups in the same module and throws a warning if type definitions within the same group are not alphabetically (or alpha-numerically, where numbers come before letters) ordered. The ordering is case-insensitive.

Grouping of Ports and Related Messages

  • Symbolic Name in XML Configuration: checkPortMessageGrouping
  • Dependant Tags in XML Configuration: -

This quality check verifies that port definitions are grouped together with all the message types or signatures referenced within the port definition. The ports and the message types / signatures related to them shall be grouped within the same group in the same module. Limited nested grouping is allowed, where the message / signatures may be grouped in a subgroup within the group in which the port to which they are related was defined. This can be best illustrated by examples:

module checkPortMessageGrouping {
    import from checkPortMessageGroupingExternal all;
    //correct examples

    group correct {
        type port port1 message {
            in m1;
            out m2, m3;
        }
        type port port2 message {
            inout m1, m3;
        }
        type port port3 message {
            inout m4, m3;
            out m1, m2;
            in integer, charstring;
            out integer;
        }
        type port port4 procedure {
            in sm1, sm2;
            out sm3, sm4;
            inout sm5, sm6;
        }
        type port port5 mixed {
            in sm1, m1;
            out integer;
        }
        group nested {
            group signatures {
                signature sm1();
                signature sm2();
                signature sm3();
                signature sm4();
                signature sm5();
                signature sm6();
            } 

        } 

        type integer m1;

        type record m2 {

        }

        type set m3 {

        }

        type record m4 {

        }

    }
    //incorrect examples 

    group incorrect {
        type port port6 message {
            in m1, m2;
            out m3;
        }
        type port port7 message {
            inout checkPortMessageGroupingExternal.m5;
            out m6;
        }
        type port port8 procedure {
            inout sm1, sm2;
            out sm3;
        }
    } 

    type record m6 {

    }

    type port port9 message {
        inout m6, m7;
    }

    group g1 {
        type set m7 {

        }
        type record m8 {

        }
    } 

}

In the above module definition, the contents of group correct are OK, where as the contents of group incorrect are not, because the message types are not defined under the same group where the port they are related to is defined.

If a port is defined outside a group, it automatically means that the related message types cannot be defined within the same group and they are not further analyzed. If a message type is defined outside a group, it also means that it is not in the same group as the port definition it is related to. If a message type is defined within a group with the same name as the one where the port it is related to is defined, but within a different module, it is also considered a violation of the constraint and a warning will be thrown. If a message type related to a port type definition cannot be resolved, it is considered a violation of the constraint as well and an appropriate warning is thrown.

The standard (first) line numbers in the output indicate the reference point - on which lines within the port type definition has the violating message type been referenced. Additionally, next to the message type / signature name and the port type name, location triples <startLine,moduleName,groupName> are provided to facilitate the easier identification and localization of the elements violating the constraint.

Additionally, if nesting is present as in the above example, but does not violate the constraints, an information message will be provided in the output to inform the user of the occurrence.

No All Keyword in Port Type Definitions

  • Symbolic Name in XML Configuration: checkNoAllKeywordInPortDefinitions
  • Dependant Tags in XML Configuration: -

The check makes sure that there are no all keywords in port type definitions.

Log Statements

Log Format Must Match the Format of a Regular Expression

  • Symbolic Name in XML Configuration: checkLogStatementFormat
  • Dependant Tags in XML Configuration: logFormatRegExp, checkLogItemFormat, processSubsequentLogStatementsAsOne

The check inspects the string in each log statement and matches it against a given regular expression. The predefined regular expression corresponds to the current ETSI guidelines. The regular expression can be adapted and customized for each profile however by changing the content of the logFormatRegExp tag in a profile of the XML configuration. In addition, the first regexp group is matched against the name of outer compound of the log statement, i.e., the function, testcase, or altstep name. If the first group is empty, the latter additional check will be ignored. That means, if T3Q shall not check for the containing construct, there must be an artificial empty first group in the specified regexp.

The current default regular expression is:

[\*]{3}\s([fta]_[a-zA-Z0-9]+?):\s(INFO|WARNING|ERROR|PASS|FAIL|INCONC|TIMEOUT):\s.*?[\*]{3}

The checkLogStatementFormat setting enables checking the whole log statement where multiple log items within a single log statement are joined as one. In case of string concatenation and/or use of non-chastring elements (e.g. variable references, constant references, parameter references, or function calls), all non-charstring elements are currently substituted by an empty string. Note that charstring elements used as parameters in e.g. function calls currently will also be taken into consideration when checking the log statement format.

For individual log items, the checkLogItemFormat setting can be enabled instead. The same regular expression is used for checking individual log items. Note that even though the same regular expression is used, both checks are independent, meaning both can be enabled at the same time, with one checking the individual log items within a log statement and the other combining those log items and checking their concatenation (ignoring non-charstring elements as noted above). Due to possible confusion introduced by this additional check and its questionable usefulness, it should be considered deprecated and will be removed in future releases.

By enabling the processSubsequentLogStatementsAsOne setting, subsequent log statements can be combined and analyzed as one (again ignoring variables within log statements), in a way similar to how log items are analyzed together within a log statement. This setting has no effect if checkLogStatementFormat is disabled.

Note that subsequent log statements (without any other statements in between) are always combined when the processSubsequentLogStatementsAsOne setting is enabled. This may in some cases lead to unreliable results, if, for example, one well-formed log statement is followed by another not well-formed one, the combination of the two may still yield a valid log statement with the setting enabled.

Note also if the processSubsequentLogStatementsAsOne setting is enabled, the subsequent log statements that are combined together are analyzed as a bundle starting with the first log statement in the sequence, meaning that the subsequent log statements are not analyzed individually again.

Example:

module checkLogFormatModule {
    function f_1 ()
    runs on myComponent {
        //incorrect
        log ( "***" )
        test();
        //correct
        log("*** f_1: INFO: OK - random value = " & bit2str(v_random) & " ***");
        test();
        //correct - function calls are ignored
        log("*** f_1: " & getMyStatus() & "INFO: OK - random value = " & bit2str(v_random) & " ***");
        test();
        //incorrect - charstring function call parameters are taken into consideration resulting in
        //an incorrect log statement format
        log("*** f_1: " & getMyStatus("1") & "INFO: OK - random value = " & bit2str(v_random) & " ***");
    }
    const integer c_1 := 1;
    testcase t_sendMsg ()
    runs on myComponent {
                //this should also be correct
                log("*** t_sendMsg: INFO: Unknown component " & p_variable & " ***");
                f_2 ();
        // correct
        log ( "*** t_sendMsg: INFO: Wrong message has been received ***" )
        f_1 (); //if this statement were absent
                //and subsequent log processing enabled
                //the above log sattement will be analyzed
                //together with the following split log statements
        // also correct, given subsequent log processing is enabled
        log ( "*** t_sendMsg: " );
        log ( "INFO: " );
        log ( "Wrong message has been received ***" );
        f_1 ();
        //correct , given subsequent log processing is enabled
        log ( "*** t_sendMsg: " );
        log ( "INFO: " );
        log ( f_2 () );
        log ( "Wrong message has been received ***" );
        f_1 ();
        // some simple malformed log statements
        //will be combined as one if subsequent log processing is enabled
        log ( "*** : INFORMATION: Wrong message has been received ***" )
        log ( "** t_sendMsg: INFO: Wrong message has been received **" )
        log ( "*** t_sendMsg22: INFO: Wrong message has been received ***" )
        log ( "*** t_sendMsg: INFORMATION: Wrong message has been received ***" )
        //correct under different configuration / not combined with the above
        log ( "*** INFO: Wrong message has been received ***" );
    }
    control {
        //incorrect
        log ( ".." );
        //correct, if not combined with the above
        log ( "*** t_sendMsg22: INFO: Wrong message has been received ***" )
    }
}

External Function Invocation Must Be Preceded By A Log Statement

  • Symbolic Name in XML Configuration: checkExternalFunctionInvocationPrecededByLogStatement
  • Dependant Tags in XML Configuration: -

Checks whether any invocation of an external function is preceded by a log statement. The examples shall generated warnings for all the invocations that do not have a log statement preceding them directly (tagged as bad).

Example:

module checkExternalFunctionInvocationFollowedByLogStatement {
        external function fx_example1();
        external function fx_example2(integer p_int) return integer;
        external function fx_example2(charstring p_cs) return charstring;
        //inconclusive - in a constant definition
        const integer c := fx_example1(1);
        //inconclusive - unresolved
        function f_example1() {
                fx_example0();
        }
        //bad - at the end of a scope
        function f_example1() {
                fx_example1();
        }
        //bad - followed
        function f_example2() {
                fx_example1();
                log("External Function fx_example1 called!")
        }
        //bad - at the end of a scope without SemiColon
        function f_example3() {
                fx_example1()
        }
        //bad - at the end of a scope without SemiColon, followed
        function f_example4() {
                fx_example1()
                log("External Function fx_example1 called!")
        }
        //multiple
        testcase tc1() runs on mtcType system systemType {
                //bad
                fx_example1();
                log("External Function fx_example1 called!")
                f_example1();
                //good
                log("External Function fx_example1 called!")
                fx_example1();
                f_example2()
                //bad
                fx_example1()
                //bad
                fx_example1();
                log("External Function fx_example1 called!")
        }
        control {
                execute(tc1());
        }
}

Note that if an external function is called within a constant or a template definition on the module level, an information message will be provided that in such a context it is not possible to have a log statement following it. Note also that if a function definition cannot be resolved, a corresponding information message will be provided as well.

Inconclusive or Fail Setverdict Statement Must be Preceded by a Log Statement

  • Symbolic Name in XML Configuration: checkInconcOrFailSetVerdictPrecededByLog
  • Dependant Tags in XML Configuration: -

Checks whether setverdict statements that set inconc or fail verdicts are preceded by log statements. In the example, the first alt statement represents the expected syntax whereas the second alt statement fails to have log statements before the two existing fail and inconc setverdict statements.

Example:

module checkInconcOrFailSetverdictPrecededByLog {
    testcase t_sendMsg() runs on myComponent {
        p1.send(msg_a);
        // this is as expected
        alt {
            [] p2.receive(msg_b) {
                someOtherfunction();
                log("*** t_sendMsg: INFO: Wrong message has been received ***")
                setverdict(fail);
                                someOtherfunction();
            }
            [] p2.receive(msg_c) {
                setverdict(pass);
            }
            [] p2.receive {
                log("*** t_sendMsg: INFO: Unexpected message, possibly malicious ***");
                setverdict(inconc);
            }
        }
        // here, the log statements are missing
        alt {
            [] p2.receive(msg_b) {
                setverdict(fail);
            }
            [] p2.receive(msg_c) {
                setverdict(pass);
            }
            [] p2.receive {
                setverdict(inconc);
            }
        }
    }
}

Code Style

There Must Be No Labels or Goto Statements

  • Symbolic Name in XML Configuration: checkNoLabelsOrGotoStatements
  • Dependant Tags in XML Configuration: -

The check makes sure that there are no labels and goto statements in the test code.

There Must Be No Nested Alt Statements

  • Symbolic Name in XML Configuration: checkNoNestedAltStatements
  • Dependant Tags in XML Configuration: maximumAllowedNestingDepth

The check makes sure that there are no alt statements nested within other alt statements or altstep definitions beyond a given depth (specified via the maximumAllowedNestingDepth configuration tag). The topmost alt or the enclosing altstep definition is considered of depth 0, first level nesting is of depth 1, and so on. The default nesting depth is 0, meaning that no alt statements are allowed within other alt statements or altstep definitions.

Example:

module checNoNestedAltStatements {
    altstep as_0 ()
    runs on myComponent {
        //nesting within an altstep
        [] p2.receive ( msg_b ) {
        }
        [] p2.receive ( msg_c ) {
            setverdict ( pass );
            // nested alt, level 1
            alt {
                [] p2.receive ( msg_b ) {
                }
                [] p2.receive ( msg_c ) {
                    setverdict ( pass );
                }
                [] p2.receive {
                }
            }
        }
        [] p2.receive {
            // nested alt, level 1
            alt {
                [] p2.receive ( msg_b ) {
                }
                [] p2.receive ( msg_c ) {
                    setverdict ( pass );
                }
                [] p2.receive {
                    // nested alt, level 2
                    alt {
                        [] p2.receive ( msg_b ) {
                        }
                        [] p2.receive ( msg_c ) {
                            setverdict ( pass );
                        }
                        [] p2.receive {
                        }
                    }
                }
            }
        }
    }
    testcase t_sendMsg ()
    runs on myComponent {
        //nesting within alt statement
        p1.send ( msg_a );
        alt {
            [] p2.receive ( msg_b ) {
            }
            [] p2.receive ( msg_c ) {
                setverdict ( pass );
                // nested alt, level 1
                alt {
                    [] p2.receive ( msg_b ) {
                    }
                    [] p2.receive ( msg_c ) {
                        setverdict ( pass );
                    }
                    [] p2.receive {
                    }
                }
            }
            [] p2.receive {
                // nested alt, level 1
                alt {
                    [] p2.receive ( msg_b ) {
                    }
                    [] p2.receive ( msg_c ) {
                        setverdict ( pass );
                    }
                    [] p2.receive {
                        // nested alt level 2
                        alt {
                            [] p2.receive ( msg_b ) {
                            }
                            [] p2.receive ( msg_c ) {
                                setverdict ( pass );
                            }
                            [] p2.receive {
                            }
                        }
                    }
                }
            }
        }
    }
}

Output

The output includes the scope of the alt statement (starting line - end line) and has the following format:

Alt statement nesting depth (<DEPTH>) exceeds maximum allowed nesting depth (<maximumAllowedNestingDepth>)!

There Must Be No Permutation Keyword

  • Symbolic Name in XML Configuration: checkNoPermutationKeyword
  • Dependant Tags in XML Configuration: -

The check makes sure that there are no permutation keywords in the test code.

There Must Be No AnyType Keyword

  • Symbolic Name in XML Configuration: checkNoAnyTypeKeyword
  • Dependant Tags in XML Configuration: -

The check makes sure that there are no anytype keywords in the test code.

There Must Be No Modified Template of a Modified Template

  • Symbolic Name in XML Configuration: checkNoModifiedTemplateOfModifiedTemplate
  • Dependant Tags in XML Configuration: -

The check makes sure that there are no modified templates are derived from modified templates. In the example, myTemplate3 is a modified template of degree 2 and myTemplate4 is a modified template of degree 4. Both will be reported by T3Q.

Example:

module checkNoModifiedTemplateOfModifiedTemplate {
    type record MyRecordType {
        integer field1 optional,
        charstring field2,
        boolean field3
    }
    template MyRecordType MyTemplate1 := {
        field1 := 123,
        field2 := "A string",
        field3 := true
    }
    template MyRecordType MyTemplate2 modifies MyTemplate1 := {
        field1 := omit,
        field2 := "A modified string"
    }
    // MyTemplate2 is already a modified template
    template MyRecordType MyTemplate3 modifies MyTemplate2 := {
        field1 := 22
    }
    // this one is even modified two times
    template MyRecordType MyTemplate4 modifies MyTemplate3 := {
        field3 := false
    }
        // NESTED TEMPLATES
        type record MyRecordType2 {
        integer field1 optional,
        charstring field2,
        boolean field3,
        MyRecordType nestedTemplate
    }
    template MyRecordType MyNestedTemplate1 := {
        field1 := 123,
        field2 := "A string",
        field3 := true,
        nestedTemplate :={field1:= 1, field2:="a", field3:=true}
    }
    template MyRecordType MyNestedTemplate2 modifies MyNestedTemplate1 := {
        field2 := "B string",
        nestedTemplate :={field1:= 2, field2:="b", field3:=true}
    }
    template MyRecordType MyNestedTemplate3 modifies MyNestedTemplate2 := {
        field2 := "C string",
        nestedTemplate :={field1:= 3, field2:="c", field3:=true}
    }
}

Local Definitions Must Be Declared at the Beginning of Testcases, Functions, Altsteps, and Component Definitions, in a Specified Order

  • Symbolic Name in XML Configuration: checkLocalDefinitionsComeFirst
  • Dependant Tags in XML Configuration: localDefinitionTypes

This is an evolved version of the check for variables only in the same context (declared before any other statements). In this version, not only variables, but also local constants and timers can be considered (if configured). Additionally, the order of occurrence of these three classes of local definitions can be specified and checked for. With the help of the help of the localDefinitionTypes configuration tag, which contains a list string tags, the contents and the order of local definitions can be specified. The default configuration contains four possible types of local definitions: VarInstance (variables), ConstDef (local constants), TimerInstance (local timers), and PortInstance (port instances, only within components), configured in this order, meaning that constants are expected to be declared after all variables and before all timers (and ports, in the context of component definitions):

      <localDefinitionTypes>
        <string>VarInstance</string>
        <string>ConstDef</string>
        <string>TimerInstance</string>
        <string>PortInstance</string>
      </localDefinitionTypes>

This order can be changed by moving the configured entries up and down the list. If timers and ports are to be disregarded, for example, then the whole configuration tags shall be omitted, so that the configuration will be:

      <localDefinitionTypes>
        <string>VarInstance</string>
        <string>ConstDef</string>
      </localDefinitionTypes>

Only the local definition types provided in the default configuration can be used, and only if spelled correctly, meaning that case-sensitivity matters in this context ("constdef" hence will not be recognized).

Note that control part definitions are not analyzed. This will be subject to change, where control part definitions will be analyzed as well.

Import Statements Must Be Declared at the Beginning of Modules

  • Symbolic Name in XML Configuration: checkImportsComeFirst
  • Dependant Tags in XML Configuration: -

Similarly to "Variables Must Be Declared at the Beginning of Testcases, Functions and Altsteps", this check makes sure that all import statements are always at the beginning of any module.

There Must Be No Duplicated Identifiers On the Module Level

  • Symbolic Name in XML Configuration: checkNoDuplicatedModuleDefinitionIdentifiers
  • Dependant Tags in XML Configuration: -

This check will make sure there are no identical identifiers for definitions on the module level among the analyzed modules (regardless of type).

There Must Be No Unused Definitions On the Module Level

  • Symbolic Name in XML Configuration: checkZeroReferencedModuleDefinitions
  • Dependant Tags in XML Configuration: zeroReferencedModuleDefinitionsExcludedRegExp

This check will make sure there are no unused definitions on the module level among the analyzed modules, including references through imports. References within import statements however will be disregarded, meaning that if a definition is imported, but never used, it will be considered an unused definition as well. Group definitions are excluded from this check. Additionally, through the zeroReferencedModuleDefinitionsExcludedRegExp configuration tag, a regular expression can be specified to allow certain modules (based on the module name) to be excluded from this check. The regular expression is empty by default, meaning that all modules are considered by default.

There Must Be No Inline Templates

  • Symbolic Name in XML Configuration: checkNoInlineTemplates
  • Dependant Tags in XML Configuration: -

This check will make sure there are no inline templates used in the analyzed modules.

There Must Be No Over-specific Runs On Clauses

  • Symbolic Name in XML Configuration: checkNoOverSpecificRunsOnClauses
  • Dependant Tags in XML Configuration: recursionInCheckNoOverSpecificRunsOnClauses, aliasInCheckNoOverSpecificRunsOnClauses (since v2.0.0b27)

This check will make sure no over-specific runs on clauses are used. An over-specific runs on clause is when none of the component element definitions (variables, timers, constants, and ports) of the component used in the runs on clause are referenced within the body of the function or alststep with the runs on clause. If at least one of the component element definitions is referenced within the body of the function or altstep, then no problem is reported. If the recursionInCheckNoOverSpecificRunsOnClauses setting is enabled (which it is by default), also the functions and altsteps referenced within the body of the current construct will be inspected. This is due to the fact that often wrapper functions are used that do not make direct use of the component element definitions themselves.

As of v1.0.3, test cases are not considered in this check, due to a change request based on the notion that test cases are required to have a runs on clause, regardless of whether they actually utilize any of the component element definitions of the MTC.

Example:

module checkNoOverSpecificRunsOn {
    //global const for validation
    const someType someGlobalConst := 21;
        //component in question
    type component someComponent {
        var someType someVarName := 2;
        var someType someOtherVarName := 2, someAnotherVarName := 4;
        var charstring someCharStringVar := "xyz";
        var template someType someTemplateVarName := 3;
        const someType someConstName := 1;
        const integer someIntegerConstName := 42;
        const someOtherType someConstName2 := someModuleParameterName2, someConstName3 := someModuleParameterName3;
        timer someTimer;
        port somePortType somePortInstance;
    }
        type component someComponent2 extends someComponent{
        port somePortType somePortInstance2;
        }
        //good
    function someFunction ()
    runs on someComponent {
        //some references to component definitions here
        someTimer.start ( 10.0 );
    }
        //bad
    function someOverSpecificFunction ()
    runs on someComponent {
                //ay(); //this will make it valid
                //wrapperfunction(); //this will make it valid
                wrapperFunction(); //unresolvable due to a typo - proper error message provided
    //no references to component definitions here
    }
        //irrelevant
    function someGenericFunction () runs on someComponent{
                somePortInstance.send("x");
    //no relation
    }
    //good
    //a tricky example with a referenced function that uses the relevant fields
    //wraper function
    function wrapperfunction ()
    runs on someComponent {
        //function that uses the component definitions
        someFunction ();
    }
        //bad
    testcase tcx ()
    runs on someComponent {
                //ay(); //this will make it valid
    }
        //good
        //tricky wrapper example
    altstep ax ()
    runs on someComponent {
        var integer a := someFunction();
        [] ay ()
        [] ay ()
    }
        //good
    altstep ay ()
    runs on someComponent {
        var integer a := someFunction();
        [] someTimer.timeout {
                        wrapperfunction();
        }
    }
        //tricky cyclic call sequences
        function f1() runs on someComponent{
                f2();
                f3()
        }
        function f2() runs on someComponent{
                f1()
                f4()
        }
        function f3() runs on someComponent{
                f2()
        }
        function f4() runs on someComponent{
        }
}

As of v2.0.0b27 an additional setting aliasInCheckNoOverSpecificRunsOnClauses is provided. It enables the special treatment of component "alias" type definitions (component type definitions without any owned definitions that extend another component type and inherit its definitions). If this setting is enabled (which it is by default), a function or an altstep specified to run on a given component type will only raise a warning if none of the definitions of the component type(s) that this component type extends directly (i.e. not considering the components extended by those components recursively) are used within the function or altstep. It supersedes the previously introduced extendsInCheckNoOverSpecificRunsOnClauses setting.

For example:

    //base component
    type component componentWithDefinition {
        timer definedTimer;
    }

    //extension with own definitions
    type component directExtension extends componentWithDefinition {
        var integer directExtensionVariable;
    }

    //multi alias / extension ("pure", without own definitions)
    type component indirectAlias extends directExtension {
        
    }

    //multi alias / extension ("pure", without own definitions)
    type component pureAlias extends componentWithDefinition {
        
    }
     
    //always good - base component
    function someFunctionOnBaseComponent ()
    runs on componentWithDefinition {
        definedTimer.start ( 10.0 );
    }

    //bad - no definition from directExtension used
    function someFunctionOnDirectAlias ()
    runs on directExtension {
        definedTimer.start ( 10.0 );
    }


    //bad - no definition from aliased directExtension used
    function someFunctionOnMultiAlias ()
    runs on indirectAlias {
        definedTimer.start ( 10.0 );
    }

    //good - definition from aliased directExtension is used (directAliasVariable)
    function someFunctionOnMultiAliasWithReferenceToVariable ()
    runs on indirectAlias {
        definedTimer.start ( 10.0 );
        directExtensionVariable := 1; 
    }

    //good - definition from aliased componentWithDefinition is used (definedTimer)
    function someFunctionOnPureAlias ()
    runs on pureAlias {
        definedTimer.start ( 10.0 );
    }

There Must Be No Unused Imports

  • Symbolic Name in XML Configuration: checkNoUnusedImports
  • Dependant Tags in XML Configuration: -

This is a rather complex quality check, that seeks to identify unused imports. As a first step it checks whether the imported module exists. If it does not exist, it is either because the imported module is not a part of the analyzed input, or because the name of the imported module has been misspelled. Whatever the case, if the module cannot be resolved, a corresponding message is provided and the check for that particular import statement is finished. If the module can be resolved, depending on the context, the following situations are checked:

  1. If an all keyword is used in a non-type-restrictive manner (i.e. not associated to a certain definition type), then it is checked whether there is at least one reference of any module definition from the imported module within the importing module. Whether there are exceptions specified in the import statement makes no difference in this case, because in such a scenario, it is no longer possible to have references pointing back to the imported definition and thus the results of this check remain correct.
  2. If a non-specific type import is used (i.e. an all keyword is preceded by definition type keyword), then it is checked whether there is at least one reference of any module definition of the given type from the imported module within the importing module. Same conditions apply as in the non-type-restrictive use of the all keyword. If all groups are to be considered, then only the definitions within groups are considered, those outside groups are not considered.
  3. If a specific type import is used (i.e. a definition type keyword, followed by a (list of) identifiers), several checks are performed:
    1. Check if the identifier is resolvable. If it is not it means that either the definition is not present within the imported module or the identifier is perhaps misspelled.
    2. If the identifier is resolvable, it is checked whether the definition is actually within the imported module. It may be the case that the definition has already been imported from another module (see also Documentation/T3Q/Quality-Checks/Code-Style), in which case a corresponding message is provided and the actual references for that identifier are not checked any further. It may also be the case that the definition has already been imported from another module, but also does not exist in the module from which it is attempted to be imported again (the definition has been moved perhaps?!), in which case another corresponding message is provided, and no further analysis of the actual references is performed.
    3. Finally, if the identifier is uniquely and correctly resolvable, is is checked whether there are any references to that imported definition within the importing module. If a specific group is imported, it is checked whether any of the definitions within that group are referenced in the importing module instead.

Note that currently this check is rather computationally expensive and thus disabled by default. Once suitable optimizations are added, it will be re-enabled by default.

There Must Be No Unused Formal Parameters

  • Symbolic Name in XML Configuration: checkNoUnusedFormalParameters
  • Dependant Tags in XML Configuration: -

This check makes sure there are no unused formal parameters. There are several peculiarities associated with this quality check:

  • External functions are excluded from this check since their formal parameters can never be used within their TTCN-3 definitions
  • In the case of modified template definitions, all the formal parameters defined in the modified template (currently matched by name only) are not checked again in the modifying template. Only the additional formal parameters defined in the modifying template are checked in such a case.
  • Type parametrization is currently left out, since type parametrization is moved to a package in TTCN-3 v4.1.1.
  • In the case of cyclic call sequences, a corresponding INFORMATION message will be generated.

There Must Be No Unused Local Definitions

  • Symbolic Name in XML Configuration: checkNoUnusedLocalDefinitions
  • Dependant Tags in XML Configuration: -

This check makes sure there are no unused local definitions. This covers local constants, timers, variables, ports, template variables and local template definitions. Currently component definitions, function definitions, altstep definitions and testcase definitions are analyzed, as well as module control parts.

There Must Be No Uninitialised Local Variables

  • Symbolic Name in XML Configuration: checkNoUninitialisedVariables
  • Dependant Tags in XML Configuration: checkNoUninitialisedVariablesExclude

This check makes sure there are no uninitialised local variables. This covers local variables declared within statement blocks or module control parts. Variables declared within components are not considered as they may or may not be initialised depending on which other behaviour constructs have been executed. Instead, the data flow analysis is performed strictly within the scope of the top-level statement block. In the following example, the state of the various variables declared within a function is described for each statement using comments directly above the statement.

    function f_ConditionalSpec() {
        var integer v_s0;
        var integer v_s1;
        var integer v_s2 := 1;
        var integer v_s3;
        var integer v_s4;
        var integer v_s5;
        
        //v_s2 is initialised upon declaration -> no warning
        if (v_s2 == 1) {
            //v_s3 is not initialised -> warning
            //v_s0 initialised within the conditional after this statement
            v_s0 := v_s3 + 1; 

            //v_s1 is not initialised -> warning
            //v_s2 is initialised -> no warning
            //v_s3 initialised within the conditional after this statement
            v_s3 := v_s2 + 1 + v_s1; 

            //v_s3 is initialised above -> no warning
            //v_s4 initialised within the conditional after this statement
            v_s4 := v_s3 + 1; 
        } else {
            //v_s2 is initialised -> no warning
            //v_s4 initialised within the else branch after this statement
            v_s4 := v_s2 + 1; 
        }

        //v_s3 is only initialised within one of the possible paths -> warning
        //v_s4 is initialised within both possible paths (within all branches of the conditional above) -> no warning
        v_s5 := v_s3 + v_s4; 
    }

For variables initialised within branching behaviour, such as if-else if-else constructs, alt statements, and call statements, the data flow analysis evaluates whether each branch directly initialises the variables with absolute certainty. If the variable is initialised in only some of the branches, then a warning is raised as it cannot be ensured that a variable will be initialised before use during execution. This also applies to nested branches. For loops, it cannot be ensured that a variable will be initialised as a loop can be skipped if the loop condition evaluates to false. In such case, variables initialised within the loop are considered as such in the subsequent statements within the loop, however, for statements outside the loop, the variable is still considered to be not initialised (unless there is explicit initialisation outside the loop).

The checkNoUninitialisedVariablesExclude setting can be used to filter out warnings for variables of certain types. The meta-types enumerated, union, record of, record, set of, set, can be listed in order to exclude warnings for all variables of the corresponding meta-type from the output, e.g. exclude all variables of all record types. Additionally, user defined concrete types can be listed as well, so that only warnings for variables of a specific type, e.g. a specific record type, are excluded from the output. In the following example configuration, all warnings for all variables of set and set of types, as well as for all variables of the type MyRecordType are excluded from the output.

      <checkNoUninitialisedVariablesExclude >
        <string>set</string>
        <string>set of</string>
        <string>MyRecordType</string>
      </checkNoUninitialisedVariablesExclude >

The meta-types enumerated, union, record of, record, set of, set, are currently set to be excluded by default when a new configuration profile is generated.

There Must Be No Literals

  • Symbolic Name in XML Configuration: checkNoLiterals
  • Dependant Tags in XML Configuration: -

This check makes sure there are no literals used, except in module parameters, template definitions, and constant definitions. Note that while in both module-level constants and local constants literals are permitted, in the case of templates, only template definitions at the module level can contain literals. Note also that currently matching symbols, boolean values, verdicts, omit-values, enumerated values, and address-values are not considered literals. This may be a subject to change.

Test Suite Modularization: Module Containment

Modules, whose identifiers contain any of the following substrings, shall contain only certain definition types, permissible for the particular type of module. These substrings will be referred to as "module restrictions" in the following, to establish a unified terminology and simplify the descriptions. All module restrictions are case-sensitive. The configuration entries are following the schema "check{ModuleRestriction}ModuleContainmentCheck", where "ModuleRestriction" is to be substituted with the particular substring. Apart from the permissible definition types, all modules allow the presence of import and group definitions. The output for the quality checks indicates the location/scope of the definition (starting line - end line) violating the particular constraints and the type of module restriction that has been recognized and applied (based on the substring that has been found in the module name). Note that, if a module name contains multiple restrictions, all the checks will be applied individually. This means that a "TypesAndValuesAndTemplates" module will first be checked for the permissible definition types for a "TypesAndValues" module and throw a warning on any other definition (be it a definition of the permissible definitions for a "!Template" module), and then the other way around for the permissible definitions in a "!Templates" module.

Note that control part definitions are allowed in all the following module containment checks. This may be subject to changes in the future (restricted to the "TestControl" modules only).

The details for the individual module restrictions are outlined below.

TypesAndValues Module Must Contain Only Type and Constant Definitions

  • Symbolic Name in XML Configuration: checkTypesAndValuesModuleContainmentCheck
  • Dependant Tags in XML Configuration: -

Any module that contains the substring TypesAndValues in its name will be analyzed. Only type and constant definitions are permitted within such a module. The example below illustrates a module which will produce warnings if this quality check is enabled. The first three definitions are type and constant definitions. However, templates, testcases, and functions must not be present in such a module. Thus, these last three module definitions will be reported as not of the permissible types.

Example:

module checkTypesAndValuesModuleContainmentCheckBad {
    import from LibCommon_time all;

    // good part
    type record MyRecordType {
        integer field1 optional,
        charstring field2,
        boolean field3
    }

    type integer myInt;

    const myInt myIntValue := 2;
    // bad part

    template MyRecordType MyTemplate1 := {
        field1 := 123, 
        field2 := "A string", 
        field3 := true
    }

    testcase t_sendMsg() runs on myComponent {
    }

    function myfunc() {
    }
        group g_1{
        
                function f_1(){
                }
        }
}

Notes: Component and port type definitions also fall under the generic "type definitions" term. Therefore, they are also allowed in a "TypesAndValues" module. This may be subject to changes in the future.

Templates Module Must Contain Only Template Definitions

  • Symbolic Name in XML Configuration: checkTemplatesModuleContainmentCheck
  • Dependant Tags in XML Configuration: -

Any module that contains the substring Templates in its name will be analyzed. Similar to the "TypesAndValues" module restriction, only template definitions are permitted within such a module. The example below illustrates a module which will produce warnings if this quality check is enabled. The first three definitions are template definitions (one is within a group). The constant and function definitions that follow, however, are not allowed within a "Templates" module and therefore will produce a warning.

Example:

module checkTemplatesModuleContainmentBad {
    import from LibCommon_time all;

    // good part, only templates
    template MyRecordType t_1 := {
        field1 := 1,
        field2 := "a",
        field3 :=true
    }

    template integer t_2 := (0,1,2,3,4,5,6,7);
    
    
    group GroupedDefs{
            template integer t_3 :=(0 .. 10);
                //bad part
                const integer c_1 := 2;
        
    }

        //bad part
        function f_2(){
        }

}

Functions Module Must Contain Only Function and Altstep Definitions

  • Symbolic Name in XML Configuration: checkFunctionsModuleContainmentCheck
  • Dependant Tags in XML Configuration: checkFunctionsModuleContainmentCheckAllowExtFunction

Any module that contains the substring Functions in its name will be analyzed. Similar to the other module restrictions, only function and altstep definitions are permitted within such a module. The example below illustrates a module which will produce warnings if this quality check is enabled. Additionally, external function definitions may (by default) or may not be allowed within such modules, depending on whether checkFunctionsModuleContainmentCheckAllowExtFunction is enabled or not.

Example:

module checkFunctionsModuleContainmentBad {
    import from LibCommon_time all;
    // good part, only functions and altsteps
    function f_1 () {
    }
    altstep a_1 () {
    }
    //bad part
    type record typeA {
        integer field1,
        boolean feild2
    }
    group GroupedDefs {
        function f_2 () {
        }
        altstep a_2 () {
        }
        const integer c_1 := 1;
    }
    //configurable part
    //depending on the configuration external functions
    //may (default) or may not be allowed
    external function ef_1 ();
}

Testcases Module Must Contain Only Testcase and Function Definitions That Are Referenced In Start Statements

  • Symbolic Name in XML Configuration: checkTestcasesModuleContainmentCheck
  • Dependant Tags in XML Configuration: -

Any module that contains the substring Testcases in its name will be analyzed. Similar to the other module restrictions, only testcase and function definitions that are referenced in start statements are permitted within such a module. The example below illustrates a module which will produce warnings if this quality check is enabled.

Example:

module checkTestcasesModuleContainmentBad {
    import from LibCommon_sync all;

    // bad module
        function f_1() runs on component_1{
        }

        testcase tc_1() runs on component_1{
                        var component_1 ptc0 := component_1.create;
                        ptc0.start(f_1());
                        ptc0.start(f_0()); // defined elsewhere
                        f_3(); //does not count - not in a start statement
        }    
        //not used in a start statement
        function f_3() runs on component_1{
        }

    //not a testcase or a function\
    const integer c_1 := 0;
    
    
    group GroupedDefs{
        //not used in a start statement
                function f_4() runs on component_1 return float{
                }

                function f_2() runs on component_1{
                        var component_1 ptc1 := component_1.create;
                        ptc1.start(f_1());
                        ptc1.start(f_0(f_4())); // does not count - used as a nested parameter
                        f_4(); //does not count - not in a start statement
                        timer t;
                        t.start(f_4()); //does not count - used in a timer start operation
                        
                }
                
                testcase tc_2() runs on component_1{
                        var component_1 ptc2 := component_1.create;
                        ptc2.start(f_1());
                        ptc2.start(f_0()); // defined elsewhere
                
                }

    }
}

ModuleParams Module Must Contain Only Modulepar Definitions

  • Symbolic Name in XML Configuration: checkModuleParamsModuleContainmentCheck
  • Dependant Tags in XML Configuration: -

Any module that contains the substring ModuleParams in its name will be analyzed. Similar to the other module restrictions, only modulepar definitions are permitted within such a module. The example below illustrates a module which will produce warnings if this quality check is enabled.

Example:

module checkModuleParamsModuleContainmentBad {
    import from LibCommon_time all;

    // good part, only module parameters
        modulepar integer mp_1;
        
        modulepar {
                integer mp_2;
                charstring mp_3;
        }
    
    //bad part
    const integer c_1 := 1;
    
    group GroupedDefs{
                modulepar integer mp_4;
                const integer c_2 := 2;
    }
}

Interface Module Must Contain Only Component, Port, and Type Definitions

  • Symbolic Name in XML Configuration: checkInterfaceModuleContainmentCheck
  • Dependant Tags in XML Configuration: -

Any module that contains the substring Interface in its name will be analyzed. Similar to the other module restrictions, only component, port, and type definitions are permitted within such a module (or generally speaking any type definition). The example below illustrates a module which will produce warnings if this quality check is enabled.

Example:

module checkInterfaceModuleContainmentBad {
    import from LibCommon_time all;

    // bad module

        type component component_1 {
        }

        type port port_1 message{
                in integer
        }
        const integer c_1 := 0;

        group g_1{
                type component component_2 {
                }
                type port port_2 message{
                        out integer
                }

                const integer c_2 := 1;
        }

        //are control parts permissible?
        control {
        
        }
            
}

TestSystem Module Must Contain Only Component and Port Definitions

  • Symbolic Name in XML Configuration: checkTestSystemModuleContainmentCheck
  • Dependant Tags in XML Configuration: -

Any module that contains the substring TestSystem in its name will be analyzed. Similar to the other module restrictions, only component type definitions are permitted within such a module. The example below illustrates a module which will produce warnings if this quality check is enabled.

Example:

module checkTestSystemModuleContainmentBad {
    import from LibCommon_time all;

    // bad module, port definitions as well

        type component component_1 {
        }

        type port port_1 message{
                in integer
        }

        group g_1{
                type component component_2 {
                }
                type port port_2 message{
                        out integer
                }

        
        }

        //are control parts permissible?
        control {
        
        }
            
}

TestControl Module Must Contain Only Control Part Definition

  • Symbolic Name in XML Configuration: checkTestControlModuleContainmentCheck
  • Dependant Tags in XML Configuration: -

Any module that contains the substring TestControl in its name will be analyzed. Similar to the other module restrictions, only control part definition is permitted within such a module. The example below illustrates a module which will produce warnings if this quality check is enabled.

Example:

module checkTestControlModuleContainmentBad {
    import from LibCommon_time all;

    //bad part

        modulepar integer mp_1;
        
        modulepar {
                integer mp_2;
                charstring mp_3;
        }
    
    
    const integer c_1 := 1;
    
    group GroupedDefs{
                modulepar integer mp_4;
                const integer c_2 := 2;
    }

        control {
        
        }

}

Test Suite Modularization: Importing Libraries

TypesAndValues Modules Must Always Import From Certain Modules

  • Symbolic Name in XML Configuration: checkTypesAndValuesModuleImportsLibNames
  • Dependant Tags in XML Configuration: typesAndValuesImportsLibNamesRegExp, typesAndValuesImportsLibNamesExcludedRegExp

The check inspects whether a module that contains TypesAndValues (case-sensitive) in its name imports from modules with certain names (e.g. libraries - LibCommon). The names of the required imports are specified by means of regular expressions. The default setting is .*?LibCommon.*, meaning that definitions shall be imported from modules that contain LibCommon in their name (regardless of the position of this substring). This setting is stored under the typesAndValuesImportsLibNamesRegExp tag in the configuration.

Additionally, with the help of the typesAndValuesImportsLibNamesExcludedRegExp setting, certain modules can be excluded from this check (e.g. modules whose identifier also contains LibCommon, such as !LibCommon_TypesAndValues). The default value for this setting is .*?LibCommon.*.

The message text in the output for this quality check is: Required imports ("$typesAndValuesImportsLibNamesRegExp") not found!

Testcases Module Must Always Import From Modules Prefixes with !LibCommon_Sync

  • Symbolic Name in XML Configuration: checkTestcasesModuleImportsLibCommon_Sync
  • Dependant Tags in XML Configuration: -

The check inspects whether a module that contains Testcases (case-sensitive) in its name imports from modules that are prefixed with the string !LibCommon_Sync (case sensitive!).

Similar conditions as in "TypesAndValues Module Must Always Import From Modules Prefixes with LibCommon" apply to this quality check as well. Modules whose identifiers contain "!LibCommon_Sync" are excluded (regardless of where the substring is placed). The configuration for this quality check will also be extended in the future to allow customized selection of the required prefix and the exclusion criteria.

Module Size

  • Symbolic Name in XML Configuration: checkModuleSize
  • Dependant Tags in XML Configuration: maximumAllowedModuleSizeInBytes

This check tests whether modules exceed a given reference size (specified by the maximumAllowedModuleSizeInBytes configuration entry). The size as the tag suggests specifies the maximum allowed module size in bytes. The default reference size is 10000 bytes (~10KB).

Note that the module size is the subject of analysis and not the file size (accounting for the fact that there may be multiple modules defined within the same file as well). Thus, this quality check may not be violated, even if a file exceeds the maximum allowed size, if there are multiple smaller modules defined within that file, which do not themselves violate the maximum allowed size constraint.

T3Q Code Formatting Feature

Starting with v0.1.1, the T3Q tool provides a feature for the automated formatting of TTCN-3 code. The feature is disabled by default and has to be manually enabled in the configuration file. This is due to the fact that the user also has to specify an output path where the formatted versions of the TTCN-3 files will be written. The output setting allows for relative paths (the directory structure will be recreated in the directory from which T3Q was called), or absolute paths (the directory structures will be recreated in a fixed destination path, independent from the location where T3Q was started). Both ways to specify the output path can be used to overwrite the original TTCN-3 resources.

Below is an extract of the settings relevant to the code formatting feature from the configuration file:

      <pathFormattedOutputPath>FORMATTED</pathFormattedOutputPath>
      <formattingParameters>
        <tabs>false</tabs>
        <unixNewline>false</unixNewline>
        <spacesBetweenAssignment>true</spacesBetweenAssignment>
        <spaceAfterComma>true</spaceAfterComma>
        <KRstyle>true</KRstyle>
        <newlineBeforeRunsOn>true</newlineBeforeRunsOn>
        <newlineBeforeSystem>true</newlineBeforeSystem>
        <newlineBeforeReturn>true</newlineBeforeReturn>
        <newlineBeforeExceptionSpec>true</newlineBeforeExceptionSpec>
        <newlineBeforeFormalPar>true</newlineBeforeFormalPar>
        <newlineAfterFormalParList>true</newlineAfterFormalParList>
        <spacesAroundParentheses>true</spacesAroundParentheses>
        <spacesCount>2</spacesCount>
        <linesBetweenModules>2</linesBetweenModules>
        <linesAfterControlPart>1</linesAfterControlPart>
        <linesAfterModuleDefinition>1</linesAfterModuleDefinition>
        <linesBetweenImportDefinitions>1</linesBetweenImportDefinitions>
      </formattingParameters>
  • <pathFormattedOutputPath>FORMATTED</pathFormattedOutputPath> - Output path for the formatted TTCN-3 files, can be relative or absolute
  • <formattingParameters - Subsection with the formatting parameters
    • <tabs>false</tabs> - Use tabs or spaces for indentation, default set to spaces
    • <unixNewline>false</unixNewline> - Use UNIX new line style, this may or may not have any visible effects on the output, depending on the editors and operating systems used
    • <spacesBetweenAssignment>true</spacesBetweenAssignment> - Add a space around assignment operators
    • <spaceAfterComma>true</spaceAfterComma> - Add a space after comma
    • <KRstyle>true</KRstyle> - Use Kernighan and Ritchie formatting style
    • <newlineBeforeRunsOn>true</newlineBeforeRunsOn> - Add a new line before runs on clauses
    • <newlineBeforeSystem>true</newlineBeforeSystem> - Add a new line before system clauses
    • <newlineBeforeReturn>true</newlineBeforeReturn> - Add a new line before return clauses
    • <newlineBeforeExceptionSpec>true</newlineBeforeExceptionSpec> - Add a new line before exception clauses
    • <newlineBeforeFormalPar>true</newlineBeforeFormalPar> - Add a new line before formal parameters, unless a single parameter is used
    • <newlineAfterFormalParList>true</newlineAfterFormalParList> - Add a new line after formal parameter lists (of more than one parameter)
    • <spacesAroundParentheses>true</spacesAroundParentheses> - Add a space around parentheses
    • <spacesCount>2</spacesCount> - Indentation depth
    • <linesBetweenModules>2</linesBetweenModules> - Number of lines between modules
    • <linesAfterControlPart>1</linesAfterControlPart> - Number of lines after control parts
    • <linesAfterModuleDefinition>1</linesAfterModuleDefinition> - Number of lines after module definitions
    • <linesBetweenImportDefinitions>1</linesAfterModuleDefinition> - Number of lines between import definitions (affects only subsequent import definitions)
  • </formattingParameters>

Upon successfully saving a formatted file, an output message is generated providing the location of the file.

Low-Level Dependencies (migrated from T3Dv1 to T3Qv2)

The generated low-level dependencies serve (currently) exclusively for custom processing by third party tools for purposes such as slicing or markup of definitions related to a particular module definition (e.g. approved / locked definitions, etc.). That is the generated content for the low-level dependencies is only in an intermediate XML format and there is no HTML view for it (since it is roughly an abstracted version of the main view). Some form of HTML presentation may become available in future releases.

The low-level dependencies can be thought of as a blend between an abstracted version of the main view and a low-level version of the import view, featuring a compact representation of the low-level dependencies at the module definition (element) level - it contains all the module definitions and all the known elements referenced directly within each module definition.

The structure of the low-level dependencies intermediate representation features a list of all elements, where for each element the following pieces of information are available:

  • A unique ID of the element so that it can be uniquely referenced
  • The name of the element as per its identifier
  • The top-level type of the element (e.g. type, function, altstep, etc.)
  • Its definition start location (the line where the definition of the element starts)
  • The name of the containing module where the element is defined
  • The name of the file containing the module where the element is defined
  • A list of the element IDs for all the elements referenced within the current element

Upon recursive resolution a dependency graph can be created for a set of related elements.

More details about the technical side of the low-level dependencies can be found in the technical documentation.

T3Q Misc Features

Several features of general usability significance are implemented to improve the usage and automation of T3Q.

List Imported Module Names

  • Symbolic Name in XML Configuration: featureListImportedModuleNames
  • Dependant Tags in XML Configuration:

If enabled, all imported modules will be listed in the form of information messages, with the following format:

[[<ImportingFilenamePath>]<ImportingFilename>]]<LineNumber>: Information: Importing 
from module "<ImportedModuleName>"...

By default, this feature is disabled.

List Imported File Names

  • Symbolic Name in XML Configuration: featureListImportedModuleFileNames
  • Dependant Tags in XML Configuration:

If enabled, all imported modules and the files they are located in (if the files are part of the input) will be listed in the form of information messages, with the following format:

[[<ImportingFilenamePath>]<ImportingFilename>]]<LineNumber>: Information: Importing 
from module "<ImportedModuleName>" located in "<ImportedModuleFileName>"...

By default, this feature is disabled.

List Importing Module Names

  • Symbolic Name in XML Configuration: featureListImportingModuleNames
  • Dependant Tags in XML Configuration:

If enabled, all modules importing the currently analyzed module will be listed in the form of information messages, with the following format:

[[<CurrentFilenamePath>]<CurrentFilename>]]<LineNumber>: Information: Module 
"<CurrentlyAnalyzedModuleName>"! is imported in module "<ImportingModuleName>"...

By default, this feature is disabled.

List Importing File Names

  • Symbolic Name in XML Configuration: featureListImportingModuleFileNames
  • Dependant Tags in XML Configuration:

If enabled, all modules importing the currently analyzed module and the files they are located in will be listed in the form of information messages, with the following format:

[[<CurrentFilenamePath>]<CurrentFilename>]]<LineNumber>: Information: Module 
"<CurrentlyAnalyzedModuleName>" is imported in module "<ImportingModuleName>" 
located in "<ImportingFileName>"!

By default, this feature is disabled.