Core grammar
The core grammar is the base, media type-agnostic language consisting of common hypermedia controls.
It can be used on its own using the .api
extension.
Supported steps
Raw Xtext grammar
grammar app.hypermedia.testing.dsl.Core with org.eclipse.xtext.common.Terminals
generate core "http://testing.hypermedia.app/dsl/core"
CoreScenario:
(entrypoint=EntrypointStep)?
(defaultHeaders=ScenarioHeadersBlock)?
(steps+=TopLevelStep)*;
TopLevelStep:
ClassBlock |
RelaxedLinkBlock;
EntrypointStep:
'ENTRYPOINT' path=STRING
;
ResponseStep:
StatusStatement |
HeaderStatement |
RepresentationStep |
FollowStatement
;
RepresentationStep:
PropertyBlock |
PropertyStatement |
LinkStep
;
LinkStep:
LinkStatement |
RelaxedLinkBlock |
StrictLinkBlock
;
Identifier: value=STRING;
Modifier: WithModifier | ExpectModifier;
ExpectModifier: 'Expect';
WithModifier: 'With';
ScenarioHeadersBlock: 'HEADERS' '{'
(headers+=RequestHeader)+
'}';
ClassBlock:
WithModifier 'Class' name=Identifier '{'
(constraints+=RepresentationConstraint)*
(children+=RepresentationStep)*
'}'
;
PropertyBlock:
modifier=Modifier 'Property' name=Identifier '{'
(constraints+=RepresentationConstraint)*
(children+=RepresentationStep)*
'}'
;
PropertyStatement:
ExpectModifier 'Property' name=Identifier expectation=(
IntValue |
DecimalValue |
BooleanValue |
StringValue)?
;
DecimalValue:
value=DECIMAL
;
BooleanValue:
value=('true' | 'false')
;
IntValue:
value=INT
;
StringValue:
value=STRING
;
StatusStatement:
ExpectModifier 'Status' status=INT
;
RelaxedLinkBlock:
WithModifier 'Link' relation=Identifier '{'
(constraints+=ResponseConstraint)*
(children+=ResponseStep)*
'}'
;
StrictLinkBlock:
ExpectModifier 'Link' relation=Identifier '{'
(constraints+=ResponseConstraint)*
(children+=ResponseStep)*
'}'
;
LinkStatement:
ExpectModifier 'Link' relation=Identifier
;
HeaderStatement:
ExpectModifier 'Header' fieldName=FieldName (exactValue=STRING | regex=MatchingRegex | variable=VARIABLE)?
;
MatchingRegex:
'Matching' pattern=STRING
;
FollowStatement:
'Follow' variable=VARIABLE
;
RequestBlock:
{RequestBlock} '{'
(headers+=RequestHeader)*
(body=RequestBody)?
'}'
;
ResponseBlock:
{ResponseBlock} '{'
(children+=ResponseStep)*
'}'
;
RequestBody:
contents=MULTILINE_BLOCK |
reference=RequestFileBody
;
ResponseConstraint:
RepresentationConstraint |
StatusConstraint
;
RepresentationConstraint:
PropertyConstraint
;
IntCondition:
operator=(EqualityOperator | InequalityOperator)
value=INT
;
StringCondition:
operator=(EqualityOperator | InequalityOperator)
value=STRING
;
DecimalCondition:
operator=(EqualityOperator | InequalityOperator)
value=DECIMAL
;
RegexCondition:
operator=('Matches' | 'Matching')
value=STRING
;
BooleanCondition:
operator=EqualityOperator
value=('true' | 'false')
;
CustomCondition:
operator='=>'
value=MULTILINE_BLOCK
;
StatusConstraint:
'When' 'Status'
negation='Not'?
condition=(IntCondition | CustomCondition)
;
PropertyConstraint:
'When' 'Property'
name=Identifier?
negation='Not'?
condition=(
IntCondition |
StringCondition |
DecimalCondition |
RegexCondition |
BooleanCondition |
CustomCondition
)
;
EqualityOperator:
'Equal' | 'Equals'
;
RegexOperator:
'Matches' | 'Matching'
;
InequalityOperator:
('Less' | 'Greater') 'Than' ('Or' 'Equal')?
;
RequestFileBody:
'<<<' path=STRING
;
RequestHeader:
fieldName=FieldName value=STRING
;
FieldName: (ID | HYPHENATED_NAME);
terminal VARIABLE: '[' ID ']';
terminal HYPHENATED_NAME: ('a'..'z' | 'A'..'Z') ('-' | 'a'..'z' | 'A'..'Z')*;
terminal MULTILINE_BLOCK:
'```' -> '```'
;
terminal DECIMAL: INT '.' INT;