Start of change

ASSERT-F and ASSERT-T (Test an assertion)

Code Factor 1 Extended Factor 2
ASSERT-F{(A)}   expression {%MSG}
ASSERT-T{(A)}   expression {%MSG}

Assertion statements provide a self-documenting way to verify correctness. For example, you can check pre-conditions at the beginning of a procedure and check post-conditions at the end of a procedure.

The assertion operations allow you to do assertion-based coding. Use control keyword ASSERT to specify the mode for assertion operations.
  • During development of your application, you operate in ASSERT(*EXCP) mode so your application fails immediately with an exception if an assertion fails.
  • After your application is deployed, if you don't want your application to fail immediately:
    • Use ASSERT(*WARN) mode if you want the information about the failed assertion to appear in the joblog to aid in problem determination later.
    • Use ASSERT(*NONE) mode to completely disable the assertions.

Assertion statements in ASSERT(*CALL) mode may be useful in a unit-testing environment since the specified program or procedure is called for every assertion statement indicating whether the assertion succeeded or failed.

Use the ASSERT-F operation to assert that a condition is false. In the following example, the programmer is asserting that variable n is not zero.

ASSERT-F n = 0 %MSG('n = 0!');
p = x / n;
Use the ASSERT-T operation to assert that a condition is true. In the following example, the programmer is asserting that the array index is still less than the number of elements in the array.

ASSERT-T (index < %elem(arr)) %MSG('The array is too small');
index += 1;
arr(index) = new_value;

The first operand of an assertion statement is the condition to be checked.

The second operand is the %MSG built-in function. For the assertion operations, %MSG allows a single message-text parameter. This form of %MSG is valid in all modes. See Rules for %MSG with one parameter.
  • For the ASSERT(*CALL) mode, you must use the form of %MSG which only allows one message-text parameter. The message-text parameter of %MSG is passed as the second parameter for the called program or procedure for every assertion operation.

    No message is sent to the joblog in ASSERT(*CALL) mode for a failed assertion.

  • For the ASSERT(*EXCP)and ASSERT(*WARN) modes:
    • You can use the form of %MSG with only one parameter. In this case, message RNX0461 is sent. The message-text parameter of %MSG is used for the replacement text of the message.
    • You can also use the form of %MSG which allows you to specify a message id and message file. If an error occurs while sending the message, such as the message file not being found, the statement fails with status code 00126 (Error sending a message).
  • For the ASSERT(*NONE) mode, you can use either form of %MSG.

The A operation extender can be used to specify that the assertion statement always operates in ASSERT(*EXCP) mode unless the ASSERT(*CALL) mode is in effect.

The ASSERT Control keyword controls how assertion operations are handled at compile time and run time.
  • With the default mode of ASSERT(*EXCP), if the assertion fails, an escape message is sent at run time to the procedure containing the assertion statement. Status code 00461 is set.
  • With the ASSERT(*WARN) mode, if the assertion fails, a diagnostic message is sent at run time to the procedure containing the assertion statement unless the A operation extender is specified indicating that the statement should always operate in ASSERT(*EXCP) mode. No status code is associated with a failed assertion with ASSERT(*WARN).
  • With the ASSERT(*NONE) mode, assertion statements are ignored at compile time unless the A operation extender is specified indicating that the statement should always operate in ASSERT(*EXCP) mode.
  • With ASSERT(*CALL:prototype-name) mode, the program or procedure identified by the prototype-name is called for every assertion statement at run time with a parameter indicating whether the assertion failed. See Rules for the prototype specified by ASSERT(*CALL:prototype-name).

Rules for %MSG with one parameter

The operand can be character, UCS-2, or graphic.

  • For the ASSERT(*EXCP) and ASSERT(*WARN) modes, the parameter is used as the replacement text for message RNX0461.

    It cannot be longer than 5000 characters when converted to the job CCSID.

    If the operand is not valid, the error message has one of the following reason codes:
    • CCSID_GRAPH_IGNORE: CCSID(*GRAPH:*IGNORE) cannot be in effect if the operand has type graphic.
    • CVT_LEN_GT_5000: The length of the operand might be greater than 5000 when converted to the job CCSID.
    • DATATYPE: The operand must have type character, UCS-2 or graphic.
    • FIGCON: It cannot be a figurative constant.
    • LEN_GT_5000: The length is greater than 5000.
  • For the ASSERT(*CALL) mode, it must be valid for the second parameter of the specified prototype-name.

Rules for the prototype specified by ASSERT(*CALL:prototype-name)

The prototype can be for a program or procedure. If the procedure is defined in the same module, it is not necessary to explicitly code the prototype.

It must have at least two parameters. The CONST keyword must be specified for every parameter.
  1. The first parameter is required. It must have type indicator. *ON is passed to this parameter if the assertion was successful and *OFF is passed if the assertion failed. For ASSERT-F, the assertion is successful if the condition is false and for ASSERT-T, the assertion is successful if the condition is true.
  2. The second parameter is required. It must have type character, UCS-2, or graphic. The message-text operand of %MSG is passed to this parameter.
  3. The third parameter is optional. If it is specified, it must have type CHAR or VARCHAR with CCSID(*UTF8). (The CCSID parameter can also be specified as CCSID(1208).) The name of the procedure containing the ASSERT-F or ASSERT-T operation is passed to this parameter. The "declaration case" of the procedure name is used.

    If the ASSERT-F or ASSERT-T operation is in the cycle-main procedure, the name of the procedure is the same as the name of the module being created.

  4. The fourth parameter is optional. If it is specified, it must have type UNS(10) or UNS(20). The statement number of the ASSERT-F or ASSERT-T is passed to this parameter.
There are additional rules for the prototype. The error message associated with these additional rules has one of the following reason codes:
  • JAVA_METHOD: The prototype cannot be a Java™ method.
  • OVERLOAD: The prototype cannot have the OVERLOAD keyword.
  • RETVAL: The prototype cannot have a return value.

Example of ASSERT(*EXCP)

In the following example, failed assertions cause an escape message to be sent to the procedure with the assertion statement.
  1. The ASSERT keyword is not specified in the Control options so the program defaults to ASSERT(*EXCP) mode.
  2. The ASSERT-F condition indicates that the programmer expects the condition item_id = 0 OR qty = 0 to be false. If either item_id = 0 or qty = 0, the assertion fails. Since %MSG is specified with only one parameter, escape message RNX0461 is issued indicating that the assertion failed.

    The program will fail with status code 00461.

  3. The ASSERT-T condition indicates that the programmer expects the condition total <= MAX to be true. If the condition is false, an escape message is sent. Since %MSG is specified with more than one parameter, escape message ORD0101 in message file ORDERMSGF is issued indicating that the nature of the problem.

    The program will fail with status code 00461.


CTL-OPT DFTACTGRP(*NO);     //  1 
...
ASSERT-F price = 0 OR qty = 0 %MSG('price, qty cannot be zero'); //  2 
...
ASSERT-T total <= MAX %MSG('ORD0101' : 'ORDERMSGF' : %char(total)); //  3 
...

Example of ASSERT(*WARN) with the A operation extender

In the following example, failed assertions usually cause a diagnostic message to be sent to the procedure with the assertion statement. If the A operation extender is specified for a specific assertion statement, a failed assertion causes an escape message to be sent.
  1. The ASSERT(*WARN) keyword is specified.
  2. The ASSERT-F condition indicates that the programmer expects the condition qty = 0 to be false. If the assertion fails, the diagnostic message will appear in the joblog, but the program will continue.
  3. The ASSERT-T condition indicates that the programmer expects the condition total <= MAX to be true. If the assertion fails, the A operation extender will cause an escape message to be sent.

    The program will fail with status code 00461.


CTL-OPT ASSERT(*WARN);     //  1 

...
ASSERT-F qty = 0  %MSG('qty cannot be zero'); //  2 
...
ASSERT-T(A) total <= MAX %MSG('total is too big'); //  3 
...

Example of ASSERT(*NONE) with the A operation extender

In the following example, assertion statements are usually ignored by the compiler. If the A operation extender is specified for a specific assertion statement, a failed assertion causes an escape message to be sent.
  1. The ASSERT(*NONE) keyword is specified.
  2. The ASSERT-F condition indicates that the programmer expects the condition qty = 0 to be false. However, this assertion is not checked by the compiler.
  3. The ASSERT-T condition indicates that the programmer expects the condition total <= MAX to be true. If the assertion fails, the A operation extender will cause an escape message to be sent.

    The program will fail with status code 00461.


CTL-OPT ASSERT(*NONE);     //  1 
...
ASSERT-F qty = 0  %MSG('qty cannot be zero'); //  2 
...
ASSERT-T(A) total <= MAX %MSG('total is too big'); //  3 
...

Example of ASSERT(*CALL) where the procedure has 2 parameters

In the following example, procedure chkAssert is called for every assertion statement.
  1. The program is in ASSERT(*CALL) mode.
  2. The ASSERT-F condition indicates that the programmer expects the condition item_id = 0 OR qty = 0 to be false.
  3. In this program, the ASSERT(*CALL) procedure is in the module so it was not necessary to code the prototype.
  4. The ok parameter is *OFF if the assertion failed and *ON otherwise. If it was the ASSERT-F operation code, ok would be *ON if the condition was false.
  5. The procedure calls another procedure to log the result of the assertion statement.
  6. If the module is compiled with DEFINE(ASSERT_ERR_TO_JOBLOG), a failed assertion will cause an escape message to be sent to the calling procedure, which is the procedure with the assertion statement. This allows the module to behave almost as though both ASSERT(*CALL) and ASSERT(*EXCP) were in effect. The difference is that the status code in the procedure with the failed assertion statement will be status code 00211, the status code for a failed call, instead of 00461, the status code for a failed assertion.

CTL-OPT ASSERT(*CALL : chkAssert);     //  1 

...
ASSERT-F price = 0 OR qty = 0 %MSG('price, qty cannot be zero'); //  2 
...

DCL-PROC chkAssert;  //  3 
   DCL-PI *N;
      ok IND CONST;  //  4 
      msg VARCHAR(100) CONST;
   END-PI;

   log_result (ok : msg);             //  5 

   /IF DEFINED(ASSERT_ERR_TO_JOBLOG)  //  6 
   IF NOT ok;
      SND-MSG *ESCAPE 'Assertion error: ' + msg;
   ENDIF;
   /ENDIF
END-PROC;

Example of ASSERT(*CALL) where the procedure has 4 parameters

In the following example, procedure chkAssert is called for every assertion statement.

The example shows an excerpt from the compile listing, showing the statement numbers. The source was compiled with OPTION(*SRCSTMT) so the statement numbers are derived from the source sequence numbers. If the source had been compiled with OPTION(*NOSRCSTMT), the statement numbers would be sequential (1, 2, 3, and so on).

  1. The program is in ASSERT(*CALL) mode. The procedure called for every ASSERT-F or ASSERT-T operation is chkAssert4Parms.
  2. The ASSERT-T statement is in the cycle-main procedure. The name passed as the third parameter of the chkAssert4Parms procedure is the name of the program or module being created. The statement number passed as the fourth parameter is 500.
  3. The symbolic name of the procedure is PROC1. The declaration case of the procedure name is Proc1.
  4. The name passed as the third parameter of the chkAssert4Parms procedure is "Proc1". The statement number passed as the fourth parameter is 1000.

                          S o u r c e   L i s t i n g
000100    CTL-OPT ASSERT(*CALL : chkAssert4Parms); //  1 
000200
000300    DCL-S n INT(10);
000400
000500    ASSERT-T n = 1 %MSG('N should be 1.');   //  2 
000600    proc1 ();
000700    RETURN;
000800
000900    DCL-PROC Proc1;                          //  3 
001000       ASSERT-T n = 2 %MSG('N should be 2'); //  4 
001100    END-PROC;
001200
001300    DCL-PROC chkAssert4Parms;
001400       DCL-PI *N;
001500          ok IND CONST;
001600          msg VARCHAR(100) CONST;
001700          procName VARCHAR(50) CCSID(*UTF8) CONST;
001800          stmt UNS(10) CONST;
001900       END-PI;
002000       // ...
002100    END-PROC;
End of change