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;
Last Updated: 7/15/2019, 3:35:47 PM