5 BDD Functions
Learn about the different types of Behavior-Driven Development functions in Oracle Communications Solution Test Automation Platform (STAP).
Overview of BDD Functions
A BDD function is a pre-defined command set that performs an operation and returns a single value. These functions are useful while performing mathematical calculations, string Concatenations (Concat), sub-strings, JSON operations, and so on.
Function arguments are separated by a comma (,). If the function arguments or variable values contain a comma, you can escape it using %{,}.
Escape only the values provided for function. If there is a comma in the context values or JSON property values escape is not required and done internally.
For example, if a comma is in the text for a variable value:
Save:
| subscriptions | Need to purchase 'premium%{,}active plan' from catalog on Tuesday and 'basic%{,}active plan on Wednesday' |
| secondPlan | %PATTERN_MATCHER(${subscriptions},'basic%{,}(.*?)',0) |
Using Response Properties and Variables in the Functions
Using Data from the Response
If you want to use a property from the response, you can access it by name if you are not using it inside a function. For example, you can assign the name property from the response to the firstName variable like this:
Save:
| firstName | name |
However, when you are using that response property inside a function, you should use a dollar sign ($) before the name, like this:
Save:
| firstName | %LOWERCASE($name)|
Using
Scenario VariablesTo use saved scenario variables as function argument, use ${<variable>}. For example,
Save:
| firstName | %LOWERCASE($name)|
| updatedFirstName | %UPPERCASE(${firstName})|
Using
functions in Validate propertyYou can use functions in validating both properties and values.
For example,
Validate:
| %ARRAY_VALUE(subscriptions[?(@.status=='ACTIVE')].plan) | Premium |
| %SUBSTRING(${notificationText},33) | test@example.com |
Validate:
| plan | %SUBSTRING(${subscriptionPlan},0,7) |
| orderID | %PATTERN_MATCHER(${orderConfirmation},\d+,0) |
String Functions
String functions are used to manipulate and handle string data.
SUBSTRING
The SUBSTRING function allows you to retrieve part of a string. You can either the part of a string that starts at a specified character number, or only a specified number of characters starting at a specified character. The format of the function is:
%SUBSTRING(string,beginIndex,noChars)
- string is either a text string or a variable
- beginIndex is he number of the character from which to start reading the string. If noChars is not present, it will read to the end of the string. Set this to 0 to read from the beginning of the string.
- noChars is optional and specifies the exact number of characters to read.
Save:
| notificationText | Notification sent at 10:30 AM to test@example.com |
Validate:
| emailID | %SUBSTRING(${notificationText},33) |
After the commands below, the plan variable contains Premium.
Save:
| subscriptionPlan | Premium Subscription Activated Successfully |
Validate:
| plan | %SUBSTRING(${subscriptionPlan},0,7) |
PATTERN_MATCHER
A pattern matcher retrieves a substring using a regular expression. In STAP, the regular expression used by the pattern matcher contains characters that need to be escaped. If these characters are not escaped, the publish scenario scripts might fail.
The following functions are used to extract specific substrings from a given string:
%PATTERN_MATCHER(<string>,<reg.exp>)Retrieves a substring which matches the given regular expression pattern.
For example,
When set variable, get the Customer information
Save:
| userMessage | Important Notice : 'Your subscription is expiring soon' |
Validate:
| extractedNotice | %PATTERN_MATCHER(${userMessage},'(.*?)',0) |
extractedNotice returns 'Your subscription is expiring soon'
%PATTERN_MATCHER(<string>,<reg.exp>,index)Retrieves a sub string at the index from the set of matches for a regular expression pattern.
For example,
When set variable, get the Customer information
Save:
| orderConfirmation | Order #INV-12345 confirmed for your subscriptionPlan |
Validate:
| orderID | %PATTERN_MATCHER(${orderConfirmation},\d+,0) |
orderID returns 12345
%PATTERN_MATCHER(<string>,<reg.exp>,index,groupIndex)- index : index of the match
- groupIndex : Group Index of the match
For example,
When set variable, get the Customer information
Save:
| notificationText | Notification sent at 10:30 AM to test@example.com |
Validate:
| emailDomain | %PATTERN_MATCHER(${notificationText},@([\w-]+)\.com,0,1) |
emailDomain returns example
Replace
The following string manipulation function is used to replace text dynamically:
%REPLACE(<search string>,<replace string>)Replaces all occurrences of the given search string with replace string.
For example,
When set variable, get the Customer information
Save:
| notificationText | Notification sent at 10:30 AM to test@example.com |
Validate:
| modifiedNotification | %REPLACE(${notificationText},test@example.com,anonymous@example.com) |
modifiedNotification returns Notification sent at 10:30 AM to anonymous@example.com
Replace First
The following string manipulation function is used to replace text dynamically:
%REPLACE_FIRST(<search string>,<replace string>)
Replaces the first occurrence of the given search string with replace string.
For example,
When set variable, get the Customer information
Save:
| orderConfirmation | Order #INV-12345 confirmed for your subscriptionPlan |
Validate:
| modifiedOrder | %REPLACE_FIRST(${orderConfirmation},O,BO) |
modifiedOrder returns Border #INV-12345 confirmed for your subscriptionPlan
Concat
The following string concatenation function is used to join multiple string arguments into a single string. It helps merge different pieces of text dynamically.
%CONCAT(<arg1>,<arg2>[,<arg3>...]) : Concatenate the given string arguments.
For example,
When set variable, getting Customer information
Save:
| subscriptionPlan | Premium Subscription Activated Successfully |
| billingDetails | Your next billing date is 15-03-2025 |
Validate:
| finalMessage | %CONCAT(${subscriptionPlan} ,${billingDetails}) |
finalMessage returns Premium Subscription Activated Successfully Your next billing date is 15-03-2025
Uppercase and Lowercase
These functions are used to convert the string into Lowercase or Uppercase.
%LOWERCASE(<string>) :Converts the given string into lowercase
%UPPERCASE(<string>) :Converts the given string into uppercase
For example,
When set variable, getting Customer information
Save:
| subscriptionPlan | Premium Subscription Activated Successfully |
| billingDetails | Your next billing date is 15-03-2025 |
Validate:
| planName | %LOWERCASE(${subscriptionPlan}) |
| nextBilling | %UPPERCASE(${billingDetails}) |
planName returns premium subscription activated successfully
nextBilling returns YOUR NEXT BILLING DATE IS 15-03-2025
Numeric Functions
Numeric functions help perform operations on numbers in various sections, including Data, Save, and Validate. They assist in rounding numbers and generating random values dynamically. For supported arithmetic expression, see Numeric Function: Evaluate to Process Arithmetic Expressions.
Rounding Numbers (%ROUND(<arg1>))
This function rounds the given numeric input to the nearest whole number (long numeric value).
For example, %ROUND(3.6) - Returns 4.
Refer to the following BDD Example:
When set variables,
Save:
| chocolates | 3.6 |
When buy chocolates,
Data:
| number | %ROUND(${chocolates}) |
Generating Random Numbers (%RANDOM())
This function returns a pseudorandom double greater than or equal to 0.0 and less than 1.0
For example, %RANDOM() - Returns 0.753524282283047
Refer to the following BDD Example:
When buy chocolates,
Data:
| number | %RANDOM() |
Numeric Function: Evaluate to Process Arithmetic Expressions
STAP supports all standard arithmetic operations, such as +,-,*,/. Specify the expression in reverse polish notation or postfix notation.
STAP requires the postfix operation for its arithmetic operations for the following reasons:
- Postfix notations are easier to parse for compiler
- Rules out the need for left - right association and precedence
- Faster to evaluate (less time for parsing)
- Can be expressed without parenthesis
- No 3rd party library dependency required
Using Arithmetic Operations
You must use the following format to perform arithmetic operations:
%EVAL(<arithmetic_operations_written_in_reverse_polish_notation>)
# each operand and operator should be comma separated
# to pass in STAP variables use: ${<variable>}
Example:
# (2+1)*3
| name | %EVAL(2,1,+,3,*) |
# (arg3+arg5)
| name | %EVAL(${arg3},${arg5},+) |
Case: Evaluate Expressions
When set variable, saving various signal datas into variables
Save:
| arg1 | 10 |
| arg2 | 9 |
| arg3 | 4 |
| arg4 | 2 |
| arg5 | 14 |
| arg6 | 20 |
When set variable, evaluating various communication fields
Save:
#| Property | Value | Runtime Value |
| signalQuality | %EVAL(2,1,+,3,*) | 9 |
| transmissionRate | %EVAL(${arg3},${arg5},+) | 18 |
| networkLatency | %EVAL(${arg1},${arg2},+,${arg3},*) | 76 |
| packetDropRate | %EVAL(${arg1},${arg2},${arg3},*,${arg4},${arg5},-,/,${arg6},*,+) | -50 |
JSON and Response Functions
- Array value
- Array size
- Response header
Array Value:
This function retrieves elements from an array using JSON Path:
- %ARRAY_VALUE(<JSON Path>): Returns the first element in the array resolved by the JSON Path.
- %ARRAY_VALUE(<JSON Path>, <index>): Returns the index element in the array resolved by the JSON Path. Index starts from 0.
The following is the response body in JSON format:
{
"user": "John Doe",
"email": "john@billing.com",
"subscriptions": [
{"plan": "Premium", "status": "ACTIVE", "expiry": "2025-03-15"},
{"plan": "Basic", "status": "EXPIRED", "expiry": "2024-01-01"}
]
}
The following are some examples of Array Value:
- Get the first email for the matched JSON Path
%ARRAY_VALUE(emails[?(@.status == 'VERIFIED')].email) returns first@email
- Get the email at index 1 for the matched JSON Path
%ARRAY_VALUE(emails[?(@.status == 'VERIFIED')].email,1) returns third@email
- Get the value at index 1 for the matched JSON Path
%ARRAY_VALUE(emails[?(@.status == 'VERIFIED')].value,1) returns 30
The following is a BDD example for an Array Value:
Then get mock response, processing Customer subscribed date and subscription details
Validate:
| firstPlan | %ARRAY_VALUE(subscriptions[?(@.status=='ACTIVE')].plan) |
| activePlanExpiry | %ARRAY_VALUE(subscriptions[?(@.status=='ACTIVE')].expiry,0) |
The following is the runtime BDD response:
Validate:
#| Property | Value | Property Value | Runtime Value | Result |
| firstPlan | %ARRAY_VALUE(subscriptions[?(@.status=='ACTIVE')].plan) Premium | Premium | PASSED |
| activePlanExpiry | %ARRAY_VALUE(subscriptions[?(@.status=='ACTIVE')].expiry,0)| 2025-03-15 | 2025-03-15 | PASSED |
| subscriptionCount | %ARRAY_SIZE(subscriptions) | 2 | 2 | PASSED |
Array Size
This function returns the number of elements in an array.
%ARRAY_SIZE(<JSON Path>) : Returns the size of the array returned by the JSON path
For example,
Validate:
#| Property | Value | Property Value | Runtime Value | Result |
| subscriptionCount | %ARRAY_SIZE(subscriptions) | 2 | 2 | PASSED |
Returns: 2 (since there are two subscription entries)
Response Header
This function returns the value for the given header key, if it is present in response headers.
For example,
{
...
"headers" : {
"transfer-encoding" : "chunked",
"connection" : "keep-alive",
"Date" : "Wed, 25 Aug 2021 04:51:40 -0700",
"Content-Type" : "application/json"
}
...
}
Get the Date header from response.
%RESPONSE_HEADER(Date) returns "Wed, 25 Aug 2021 04:51:40 -0700"
The following is a BDD example for using %RESPONSE_HEADER() in Save block:
Then get mock response, processing Customer subscription details
Save:
| Date | %RESPONSE_HEADER(Date) |
| Connection | %RESPONSE_HEADER(connection) |
The following is the runtime BDD response for using %RESPONSE_HEADER() in Save block:
Then get mock response, processing Customer subscription details
Save:
#| Property | Value | Runtime Value |
| Date | %RESPONSE_HEADER(Date) | Wed, 25 Aug 2021 04:51:36 -0700 |
| Connection | %RESPONSE_HEADER(connection) | keep-alive |
The following is a BDD example for using %RESPONSE_HEADER() in Validate block:
Then get mock response, processing Customer subscription details
Validate:
| %RESPONSE_HEADER(connection) | ${connection} |
The following is the runtime BDD response for using %RESPONSE_HEADER() in Validate block:
Then get mock response, processing Customer subscription details
Validate:
#| Property | Value | Property Value | Runtime Value | Result |
| %RESPONSE_HEADER(connection) | ${connection} | keep-alive | keep-alive | PASSED |
Data Type Functions
Data Type functions are used in Data block to represent the type of property value. By default, all data is treated as a string. To convert data to other types, use the appropriate data type functions.
Table 5-1 describes Data Type functions used in Data block to represent the type of property value.
Table 5-1 Data Type Functions
Function | Description | Example: Data |
---|---|---|
%INT(<int value>) | To represent integer values | %INT(200) -→ "value": 200 |
%DOUBLE(<double value>) | To represent floating/double values | %DOUBLE(35.75) -→ "billAmount": 35.75 |
%BOOLEAN(<boolean value>) | To represent boolean values | %BOOLEAN(true) →> "created" : true |
Date Type Functions
These functions retrieve, modify, and transform dates in various formats and are useful for timestamping, scheduling, and handling date-based calculations.
Retrieve Current Date (%NOW())
Returns current date in YYYY-MM-ddTHH:mm:ss.SSSZ format. For example,
%NOW() → "2021-08-25T14:16:28.312Z"
The following is a BDD example for retrieving current date:
When add todo task, for booking appointment
Data: Table 5-2 lists out the values in NOW format.
Table 5-2 NOW format
Property | Value | Runtime Value |
---|---|---|
description | %NOW() | 2021-08-25T14:16:28.312Z |
Retrieve Current Date in a Custom Format (%NOW(<format>))
Returns current date in specified format. For example,
%NOW(YYYY-MM-dd) → "2021-08-25"
The following is a BDD example for retrieving current date in a custom format:
When add todo task, for booking appointment
Data: Table 5-3 lists out the values in NOW format.
Table 5-3 NOW format
Property | Value | Runtime Value |
---|---|---|
description | %NOW(YYYY-MM-dd) | 2021-08-25 |
For more information on formatting the date, see Class SimpleDateFormat in Oracle Java documentation.
Add or Subtract Time (%NOWADD(<field>, <+/- value>))
Modifies the current date or time by adding or subtracting a specific amount from a time field.
Default format (YYYY-MM-dd'T'HH:mm:ss.SSS'Z')
For example, | dateTime | %NOWADD(5,10) | # Adds 10 units to field 5
| dateTime | %NOWADD(5,-10) | # Subtracts 10 units from field 5
Custom Format (%NOWADD(<field>, <+/- value>, <output format>))
For example, | dateTime | %NOWADD(5,10,yyyy-MM-dd HH:mm:ss) |
"2024-05-07 10:10:10"
Modify a Saved Date (%NOWADD(<field>, <+/- value><output format>))
Adds or Subtracts from a date field and returns date in specified format.
# Add or Subtract from current time using Custom Format
| dateTime | %NOWADD(5,10,yyyy-MM-dd HH:mm:ss) |
%DATEADD(<field>, <+/- value>)
Add/Subtract from a date field and returns date in default format YYYY-MM-dd'T'HH:mm:ss.SSS'Z'.
For example, | dateTime | %DATEADD(${datavar},5,5,yyyy-MM-dd
HH:mm:ss) |
Advanced example, (%DATEADD(<field>, <+/- value>, <input format>, <output format>):
| dateTime | %DATEADD(2024-05-07 10:10:10,5,-5,yyyy-MM-dd HH:mm:ss,dd-MM-YYYY) |
Transforms: "2024-05-07 10:10:10" → "07-05-2024"
Transform Date Formats (%TRANSFORM(<date1><inputFormat><outputFormat>))
Transforms given date in the input format to specified output format.
The following BDD example uses Transform function to trasnform date in the Save section to specified format:
When execute mock action, reading the task
Data:
| $request | $arraydata2 |
Save:
| dateTime | %TRANSFORM(2024-05-07 10:10:10,YYYY-MM-dd HH:mm:ss,dd-MM-YYY) |
Format Number Functions
The Format Number function formats a numeric value according to a specified pattern, applying different rounding modes as needed such as FLOOR, CEILING, and ROUND. It supports various separators, custom decimal places, and string interpolation within the formatted output.
Table 5-4 describes variants of Format Number Functions.
Table 5-4 Variants and Descriptions
Variant | Description |
---|---|
CEILING | Rounding mode to round towards positive infinity. |
DOWN | Rounding mode to round towards zero. |
FLOOR | Rounding mode to round towards negative infinity. |
HALF_DOWN | Rounding mode to round towards nearest neighbor unless both neighbors are equidistant, in which case you round down instead. |
HALF_EVEN | Rounding mode to round towards the nearest neighbor unless both neighbors are equidistant, in which case, round towards the even neighbor. |
HALF_UP | Rounding mode to round towards nearest neighbor unless both neighbors are equidistant, in which case you round up instead. |
UNNECESSARY | Rounding mode to assert that the requested operation has an exact result, hence no rounding is necessary. |
UP | Rounding mode to round away from zero. |
The following example shows the BDD code to format a number:
Case: Format Number
When set variable, customer bill value is taken as input
Save:
| price | 1234567.89 |
When set variable, to get formatted customer bill details
Save:
| formattedBill | %FORMAT_NUMBER(481.195) |
| decimalBill | %FORMAT_NUMBER(${price},0.0) |
| roundedBill | %FORMAT_NUMBER(${price},0) |
| roundedBill2 | %FORMAT_NUMBER(${price},#.##,CEILING) |
| roundedBill3 | %FORMAT_NUMBER(${price},#%{,}###.##,CEILING) |
| roundedBill4 | %FORMAT_NUMBER(${price},Amount to be payable is $#%{,}###.# for this month,CEILING) |
| discountedBill | %FORMAT_NUMBER(${price},#,FLOOR) |
| discountedBill1 | %FORMAT_NUMBER(${price},#,HALF_EVEN) |
| discountedBill2 | %FORMAT_NUMBER(${price},#,HALF_UP) |
| discountedBill3 | %FORMAT_NUMBER(${price},#,HALF_DOWN) |
Output (Runtime BDD):
When set variable, to get formatted customer bill details
Save:
#| Property | Value | Runtime Value |
| price | 1234567.89 | 1234567.89 |
| test | 12.053548387096775 | 12.053548387096775 |
| formattedBill | %FORMAT_NUMBER(481.195) | 481.20 |
| decimalBill | %FORMAT_NUMBER(${price},0.0) | 1234567.9 |
| roundedBill | %FORMAT_NUMBER(${price},0) | 1234568 |
| roundedBill2 | %FORMAT_NUMBER(${price},#.##,CEILING) | 1234567.89 |
| roundedBill3 | %FORMAT_NUMBER(${price},#%{,}###.##,CEILING) | 1,234,567.89 |
| roundedBill4 | %FORMAT_NUMBER(${price},Amount to be payable is $#%{,}###.# for this month,CEILING) | Amount to be payable is $1,234,567.9 for this month |
| discountedBill | %FORMAT_NUMBER(${price},#,FLOOR) | 1234567 |
| discountedBill1 | %FORMAT_NUMBER(${price},#,HALF_EVEN) | 1234568 |
| discountedBill2 | %FORMAT_NUMBER(${price},#,HALF_UP) | 1234568 |
| discountedBill3 | %FORMAT_NUMBER(${price},#,HALF_DOWN) | 1234568 |
Format Patterns
DecimalFormat is a concrete subclass of NumberFormat that formats decimal numbers. It has a variety of features designed to parse and format numbers in any locale, including support for Western, Arabic, and Indic digits. It also supports different kinds of numbers, including integers (123), fixed-point numbers (123.4), scientific notation (1.23E4), percentages (12%), and currency amounts ($123). All of these can be localized.
To obtain a NumberFormat for a specific locale, including the default locale, use one of NumberFormat's factory methods, such as getInstance(). In general, avoid using the DecimalFormat constructors directly, since the NumberFormat factory methods may return subclasses other than DecimalFormat. A DecimalFormat comprises a pattern and a set of symbols. The pattern may be set directly using applyPattern(), or indirectly using the API methods. The symbols are stored in a DecimalFormatSymbols object. When using the NumberFormat factory methods, the pattern and symbols are read from localized ResourceBundles. To customize format object, perform the following action:
A DecimalFormat comprises a pattern and a set of symbols. The pattern may be set directly using applyPattern(), or indirectly using the API methods. The symbols are stored in a DecimalFormatSymbols object. When using the NumberFormat factory methods, the pattern and symbols are read from localized ResourceBundles.
Patterns
DecimalFormat patterns have the following syntax:
Pattern:
PositivePattern
PositivePattern ; NegativePattern
PositivePattern:
Prefixopt Number Suffixopt
NegativePattern:
Prefixopt Number Suffixopt
Prefix:
any Unicode characters except \uFFFE, \uFFFF, and special characters
Suffix:
any Unicode characters except \uFFFE, \uFFFF, and special characters
Number:
Integer Exponentopt
Integer . Fraction Exponentopt
Integer:
MinimumInteger
#
# Integer
# , Integer
MinimumInteger:
0
0 MinimumInteger
0 , MinimumInteger
Fraction:
MinimumFractionopt OptionalFractionopt
MinimumFraction:
0 MinimumFractionopt
OptionalFraction:
# OptionalFractionopt
Exponent:
E MinimumExponent
MinimumExponent:
0 MinimumExponentopt
Understanding DecimalFormat Patterns
DecimalFormat patterns help format numerical values for proper display. They define prefixes, numeric values, and suffixes while handling positive and negative subpatterns, separators, and formatting symbols.
The following are the key features of DecimalFormat Patterns:
- Contains positive and negative subpatterns (for example, `"#,##0.00;(#,##0.00)"`).
- If no negative subpattern is provided, the positive pattern is prefixed with a localized minus sign (`'-'` in most locales).
- Customizable prefixes and suffixes can be used for different formatting styles.
- `"0.00"` is equivalent to `"0.00;-0.00"` since the minus sign is automatically applied.
- If a negative subpattern is explicitly defined, only the prefix and suffix
change while the numerical rules remain the same.
For example, `"#,##0.0#;(#)"` behaves exactly the same as `"#,##0.0#;(#,##0.0#)"`.
Formatting Symbols and Separators
Symbols for infinity (`∞`), digits (`0-9`), thousand separators (`,`), and decimal points (`.`) are fully customizable. Care must be taken to avoid conflicts to ensure:
- Positive and negative prefixes or suffixes are distinct for accurate parsing.
- Decimal separator and thousand separator are unique to prevent errors.
Grouping Separators and their Behavior
Typically used for thousands, though some locales use them for ten-thousands. The grouping size determines the digit intervals.
For example, `3` for `"100,000,000"` or `4` for `"1,0000,0000"`.
If multiple grouping characters are provided, the last grouping separator before the integer end is used. For example, `"#,##,###,####"` == `"######,####"` == `"##,####,####"`.