Skip to content
This repository has been archived by the owner on Apr 14, 2023. It is now read-only.

Commit

Permalink
Merge pull request #1449 from finos/create-if-constraint-cucumber-hook
Browse files Browse the repository at this point in the history
chore(#0): Added cucumber hooks for if, anyOf, and allOf
  • Loading branch information
hashbyhayter authored Oct 11, 2019
2 parents 83deaa3 + aeed42e commit 329297c
Show file tree
Hide file tree
Showing 11 changed files with 836 additions and 1,631 deletions.
113 changes: 113 additions & 0 deletions docs/developer/CucumberCookbook.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ Operators are converted to English language equivalents for use in cucumber, so
* _there is a constraint:_, adds the given JSON block as a constraint as if it was read from the profile file itself. It should only be used where the constraint cannot otherwise be expressed, e.g. for `anyOf`, `allOf` and `if`.
* _the maximum string length is {length}_, sets the maximum length for strings to the _max_ for the given scenario. The default is _200_ (for performance reasons), however in production the limit is _1000_.


#### Operands
When specifying the operator/s for a field, ensure to format the value as in the table below:

Expand Down Expand Up @@ -65,6 +66,118 @@ And there is a constraint:
"""
```

### Grammatical Constraints

Grammatical constraints (`anyOf`, `allOf`, and `if`) are supported within the cucumber hooks for more complex behaviour. These hooks expect constraints to follow the step and these constraints are grouped into the grammatical constraint. All of these hooks can be nested.

### if

* _If and Then are described below_, adds an if constraint to the profile. This expects 2 contraints to follow the step with the first constraint being mapped to the if statement and the second constraint to the then block.
* _If Then and Else are described below_, adds an if constraint to the profile. This expects 3 contraints to follow the step with the first constraint being mapped to the if statement, the second constraint to the then block, and the third constraint to the else block.

Below shows how the conversion from a JSON profile to the steps should appear:

__Json Constraint__

```json
{
"if": { "field": "foo", "is": "equalTo", "value": "dddd" },
"then": { "field": "bar", "is": "equalTo", "value": "4444" },
"else": { "field": "bar", "is": "shorterThan", "value": 1 }
}
```

__Cucumber Steps__

```json
When If Then and Else are described below
And foo is equal to "dddd"
And bar is equal to "4444"
And bar is shorter than 1
```

#### anyOf

* _Any Of the next {number} constraints_, adds an anyOf constraint to the profile. The next x number of constraints will be added to the constraint where x is the provided number

Below shows how the conversion from a JSON profile to the steps should appear:

__Json Constraint__

```json
{
"anyOf": [
{ "field": "foo", "is": "equalTo", "value": "Test0" },
{ "field": "foo", "is": "matchingRegex", "value": "[a-b]{4}" }
]
}
```

__Cucumber Steps__

```json
And Any Of the next 2 constraints
And foo is equal to "Test0"
And foo is matching regex "[a-b]{4}"
```

#### allOf

* _All Of the next {number} constraints_, adds an allOf constraint to the profile. The next x number of constraints will be added to the constraint where x is the provided number

Below shows how the conversion from a JSON profile to the steps should appear:

__Json Constraint__

```json
{
"allOf": [
{ "field": "foo", "is": "equalTo", "value": "Test0" },
{ "field": "foo", "is": "matchingRegex", "value": "[a-b]{4}" }
]
}
```

__Cucumber Steps__

```json
And All Of the next 2 constraints
And foo is equal to "Test0"
And foo is matching regex "[a-b]{4}"
```

#### Nesting Behaviour

The grammatical constraints can be nested with the processing behaving like Polish notation, an example can be seen below:

__Json Constraint__

```json
{
"allOf": [
{
"anyOf": [
{ "field": "foo", "is": "equalTo", "value": "Test0" },
{ "field": "foo", "is": "equalTo", "value": "Test2" },
{ "field": "foo", "is": "equalTo", "value": "Test4" }
]
},
{ "field": "foo", "is": "matchingRegex", "value": "[a-b]{4}" }
]
}
```

__Cucumber Steps__

```json
And All Of the next 2 constraints
And Any Of the next 3 constraints
And foo is equal to "Test0"
And foo is equal to "Test2"
And foo is equal to "Test4"
And foo is matching regex "[a-b]{4}"
```

### Describing the outcome
* _the profile is invalid because "`{reason}`"_, executes the generator and asserts that an `InvalidProfileException` or `JsonParseException` was thrown with the message `{reason}`, reason is a regular expression*.
* _no data is created_, executes the generator and asserts that no data was emitted
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,41 +10,20 @@ Feature: Generator can produce correct data for complex profiles.
And foo is anything but null
And bar has type "integer"
And bar is anything but null
And there is a constraint:
"""
{
"anyOf": [
{
"allOf": [
{
"anyOf": [
{ "field": "bar", "is": "equalTo", "value": 1 },
{ "field": "bar", "is": "equalTo", "value": 2 }
]
},
{
"anyOf": [
{ "field": "foo", "is": "equalTo", "value": 1 },
{ "field": "bar", "is": "equalTo", "value": 3 }
]
},
{
"anyOf": [
{ "field": "foo", "is": "equalTo", "value": 2 },
{ "field": "bar", "is": "equalTo", "value": 4 }
]
}
]
},
{
"allOf": [
{ "field": "foo", "is": "equalTo", "value": 10 },
{ "field": "bar", "is": "equalTo", "value": 10 }
]
}
]
}
"""
And Any Of the next 2 constraints
And All Of the next 3 constraints
And Any Of the next 2 constraints
And bar is equal to 1
And bar is equal to 2
And Any Of the next 2 constraints
And foo is equal to 1
And bar is equal to 3
And Any Of the next 2 constraints
And foo is equal to 2
And bar is equal to 4
And All Of the next 2 constraints
And foo is equal to 10
And bar is equal to 10
Then the following data should be generated:
| foo | bar |
| 10 | 10 |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -665,22 +665,16 @@ Feature: User can create data across multiple fields for all combinations availa
| "test100" |
| "other" |
| "Not in If" |
And there is a constraint:
"""
{
"if": { "field": "foo2", "is": "equalTo", "value": 1 },
"then": { "field": "foo3", "is": "equalTo", "value": "test1" },
"else": {
"if": { "field": "foo2", "is": "equalTo", "value": 10 },
"then": { "field": "foo3", "is": "equalTo", "value": "test10" },
"else": {
"if": { "field": "foo2", "is": "equalTo", "value": 100 },
"then": { "field": "foo3", "is": "equalTo", "value": "test100" },
"else": { "field": "foo3", "is": "equalTo", "value": "other" }
}
}
}
"""
When If Then and Else are described below
And foo2 is equal to 1
And foo3 is equal to "test1"
And If Then and Else are described below
And foo2 is equal to 10
And foo3 is equal to "test10"
And If Then and Else are described below
And foo2 is equal to 100
And foo3 is equal to "test100"
And foo3 is equal to "other"
Then the following data should be generated:
| foo1 | foo2 | foo3 |
| "alpha" | 1 | "test1" |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1454,13 +1454,13 @@ Feature: User can specify that a field value belongs to a set of predetermined o
Given there is a field foo
And foo has type "string"
And foo is anything but null
And there is a constraint:
"""
{ "anyOf": [
{ "field": "foo", "is": "inSet", "values": [ "Test 1", "Test 2" ] },
{ "field": "foo", "is": "inSet", "values": [ "Test 3", "Test 4" ] }
]}
"""
And Any Of the next 2 constraints
And foo is in set:
| "Test 1" |
| "Test 2" |
And foo is in set:
| "Test 3" |
| "Test 4" |
Then the following data should be generated:
| foo |
| "Test 1" |
Expand All @@ -1471,13 +1471,13 @@ Feature: User can specify that a field value belongs to a set of predetermined o
Scenario: Running a 'inSet' request as part of a non-contradicting allOf constraint should be successful
Given there is a field foo
And foo has type "string"
And there is a constraint:
"""
{ "allOf": [
{ "field": "foo", "is": "inSet", "values": [ "Test1", "Test2" ] },
{ "field": "foo", "is": "inSet", "values": [ "Test1", "Test2" ] }
]}
"""
And All Of the next 2 constraints
And foo is in set:
| "Test1" |
| "Test2" |
And foo is in set:
| "Test1" |
| "Test2" |
Then the following data should be generated:
| foo |
| null |
Expand All @@ -1487,13 +1487,13 @@ Feature: User can specify that a field value belongs to a set of predetermined o
Scenario: Running a 'inSet' request as part of a contradicting allOf constraint should produce null
Given there is a field foo
And foo has type "string"
And there is a constraint:
"""
{ "allOf": [
{ "field": "foo", "is": "inSet", "values": [ "Test1", "Test2" ] },
{ "field": "foo", "is": "inSet", "values": [ "Test3", "Test4" ] }
]}
"""
And All Of the next 2 constraints
And foo is in set:
| "Test 1" |
| "Test 2" |
And foo is in set:
| "Test 3" |
| "Test 4" |
Then the following data should be generated:
| foo |
| null |
Expand All @@ -1510,14 +1510,12 @@ Feature: User can specify that a field value belongs to a set of predetermined o
| "Test2" |
| "Test3" |
| "Test4" |
And there is a constraint:
"""
{
"if": { "field": "foo", "is": "inSet", "values": [ "Test1", "Test2" ] },
"then": { "field": "price", "is": "equalTo", "value": 1 },
"else": { "field": "price", "is": "equalTo", "value": 2 }
}
"""
When If Then and Else are described below
And foo is in set:
| "Test1" |
| "Test2" |
And price is equal to 1
And price is equal to 2
And foo is anything but null
And price is anything but null
Then the following data should be generated:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,12 @@ Feature: User can specify that data must be created to conform to each of multip

Scenario: Running an 'allOf' request that contains a valid nested allOf request should be successful
Given there is a field foo
And All Of the next 2 constraints
And All Of the next 2 constraints
And foo is matching regex "[a-b]{2}"
And foo is of length 2
And foo is shorter than 3
And foo has type "string"
And there is a constraint:
"""
{ "allOf": [
{ "allOf": [
{ "field": "foo", "is": "matchingRegex", "value": "[a-b]{2}" },
{ "field": "foo", "is": "ofLength", "value": 2 }
]},
{ "field": "foo", "is": "shorterThan", "value": 3 }
]}
"""
Then the following data should be generated:
| foo |
| "aa" |
Expand All @@ -27,42 +22,29 @@ Feature: User can specify that data must be created to conform to each of multip
Scenario: Running an 'allOf' request that contains an invalid nested allOf request should generate null
Given there is a field foo
And foo has type "string"
And there is a constraint:
"""
{ "allOf": [
{ "allOf": [
{"field": "foo", "is": "matchingRegex", "value": "[a-k]{3}" },
{"field": "foo", "is": "matchingRegex", "value": "[1-5]{3}" }
]},
{ "field": "foo", "is": "longerThan", "value": 4 }
]}
"""
And All Of the next 2 constraints
And All Of the next 2 constraints
And foo is matching regex "[a-k]{3}"
And foo is matching regex "[1-5]{3}"
And foo is longer than 4
Then the following data should be generated:
| foo |
| null |

Scenario: Running a 'allOf' request that includes multiple values within the same statement should be successful
Given there is a field foo
And foo has type "string"
And there is a constraint:
"""
{ "allOf": [
{ "field": "foo", "is": "equalTo", "value": "Test01" },
{ "field": "foo", "is": "equalTo", "value": "Test01" }
]}
"""
And All Of the next 2 constraints
And foo is equal to "Test01"
And foo is equal to "Test01"
Then the following data should be generated:
| foo |
| "Test01" |

Scenario: User attempts to combine two constraints that only intersect at the empty set within an allOf operator should not generate data
Given there is a field foo
And foo has type "string"
And there is a constraint:
"""
{ "allOf": [
{ "field": "foo", "is": "equalTo", "value": "Test0" },
{ "field": "foo", "is": "equalTo", "value": "5" }
]}
"""
And All Of the next 2 constraints
And foo is equal to "Test01"
And foo is equal to "5"
Then no data is created
Loading

0 comments on commit 329297c

Please sign in to comment.