Skip to content
Permalink
Browse files

Closes #43

  • Loading branch information...
thiagodp committed Jun 18, 2019
1 parent eb84c6a commit 616355b5d692b4a91984ad8f714c75b04dba697d
Showing with 762 additions and 324 deletions.
  1. +20 −3 __tests__/lexer/TagLexerTest.spec.ts
  2. +1 −2 __tests__/semantic/TestCaseSSATest.spec.ts
  3. +2 −2 __tests__/testcase/TCGenTest.spec.ts
  4. +2 −0 data/pt.json
  5. +2 −0 dist/data/pt.json
  6. +2 −2 dist/modules/app/TCGenController.js
  7. +2 −0 dist/modules/dict/EnglishKeywordDictionary.js
  8. +25 −7 dist/modules/lexer/Lexer.js
  9. +46 −1 dist/modules/lexer/TagLexer.js
  10. +2 −2 dist/modules/parser/AfterAllParser.js
  11. +3 −3 dist/modules/parser/AfterEachScenarioParser.js
  12. +3 −3 dist/modules/parser/AfterFeatureParser.js
  13. +4 −4 dist/modules/parser/BackgroundParser.js
  14. +2 −2 dist/modules/parser/BeforeAllParser.js
  15. +3 −3 dist/modules/parser/BeforeEachScenarioParser.js
  16. +3 −3 dist/modules/parser/BeforeFeatureParser.js
  17. +2 −2 dist/modules/parser/ConstantBlockParser.js
  18. +3 −3 dist/modules/parser/ConstantParser.js
  19. +3 −3 dist/modules/parser/DatabasePropertyParser.js
  20. +2 −2 dist/modules/parser/FeatureParser.js
  21. +2 −2 dist/modules/parser/ImportParser.js
  22. +4 −4 dist/modules/parser/LanguageParser.js
  23. +1 −1 dist/modules/parser/ListItemParser.js
  24. +3 −3 dist/modules/parser/Parser.js
  25. +2 −2 dist/modules/parser/RegexBlockParser.js
  26. +3 −3 dist/modules/parser/RegexParser.js
  27. +2 −2 dist/modules/parser/ScenarioParser.js
  28. +4 −4 dist/modules/parser/StepAndParser.js
  29. +4 −4 dist/modules/parser/StepGivenParser.js
  30. +2 −2 dist/modules/parser/StepOtherwiseParser.js
  31. +5 −5 dist/modules/parser/StepThenParser.js
  32. +4 −4 dist/modules/parser/StepWhenParser.js
  33. +2 −2 dist/modules/parser/TableRowParser.js
  34. +2 −2 dist/modules/parser/TestCaseParser.js
  35. +6 −5 dist/modules/parser/UIElementParser.js
  36. +10 −3 dist/modules/parser/UIPropertyParser.js
  37. +4 −4 dist/modules/parser/VariantBackgroundParser.js
  38. +2 −2 dist/modules/parser/VariantParser.js
  39. +1 −0 dist/modules/req/Keywords.js
  40. +0 −18 dist/modules/req/ReservedTags.js
  41. +3 −3 dist/modules/req/{SyntaticException.js → SyntacticException.js}
  42. +2 −2 dist/modules/selection/CriteriaMatcher.js
  43. +9 −9 dist/modules/testcase/TCGen.js
  44. +99 −29 dist/modules/testdata/DataTestCaseAnalyzer.js
  45. +1 −1 dist/modules/testdata/UIElementValueGenerator.js
  46. +1 −1 dist/modules/testscript/AbstractTestScriptGenerator.js
  47. +6 −2 dist/modules/util/UIElementPropertyExtractor.js
  48. +1 −2 modules/app/TCGenController.ts
  49. +2 −0 modules/dict/EnglishKeywordDictionary.ts
  50. +2 −0 modules/dict/KeywordDictionary.ts
  51. +36 −9 modules/lexer/Lexer.ts
  52. +57 −2 modules/lexer/TagLexer.ts
  53. +2 −2 modules/parser/AfterAllParser.ts
  54. +3 −3 modules/parser/AfterEachScenarioParser.ts
  55. +3 −3 modules/parser/AfterFeatureParser.ts
  56. +4 −4 modules/parser/BackgroundParser.ts
  57. +2 −2 modules/parser/BeforeAllParser.ts
  58. +3 −3 modules/parser/BeforeEachScenarioParser.ts
  59. +3 −3 modules/parser/BeforeFeatureParser.ts
  60. +2 −2 modules/parser/ConstantBlockParser.ts
  61. +3 −3 modules/parser/ConstantParser.ts
  62. +3 −3 modules/parser/DatabasePropertyParser.ts
  63. +2 −2 modules/parser/FeatureParser.ts
  64. +2 −2 modules/parser/ImportParser.ts
  65. +4 −4 modules/parser/LanguageParser.ts
  66. +1 −1 modules/parser/ListItemNodeParser.ts
  67. +1 −1 modules/parser/ListItemParser.ts
  68. +3 −3 modules/parser/Parser.ts
  69. +1 −0 modules/parser/ParsingContext.ts
  70. +2 −2 modules/parser/RegexBlockParser.ts
  71. +3 −3 modules/parser/RegexParser.ts
  72. +2 −2 modules/parser/ScenarioParser.ts
  73. +4 −4 modules/parser/StepAndParser.ts
  74. +4 −4 modules/parser/StepGivenParser.ts
  75. +2 −2 modules/parser/StepOtherwiseParser.ts
  76. +5 −5 modules/parser/StepThenParser.ts
  77. +4 −4 modules/parser/StepWhenParser.ts
  78. +2 −2 modules/parser/TableRowParser.ts
  79. +2 −2 modules/parser/TestCaseParser.ts
  80. +6 −7 modules/parser/UIElementParser.ts
  81. +11 −3 modules/parser/UIPropertyParser.ts
  82. +4 −4 modules/parser/VariantBackgroundParser.ts
  83. +2 −2 modules/parser/VariantParser.ts
  84. +1 −0 modules/req/Keywords.ts
  85. +0 −19 modules/req/ReservedTags.ts
  86. +2 −2 modules/req/{SyntaticException.ts → SyntacticException.ts}
  87. +1 −2 modules/selection/CriteriaMatcher.ts
  88. +4 −5 modules/testcase/TCGen.ts
  89. +121 −20 modules/testdata/DataTestCaseAnalyzer.ts
  90. +1 −1 modules/testdata/UIElementValueGenerator.ts
  91. +1 −1 modules/testscript/AbstractTestScriptGenerator.ts
  92. +6 −2 modules/util/UIElementPropertyExtractor.ts
  93. +114 −4 package-lock.json
  94. +2 −2 package.json
@@ -1,5 +1,6 @@
import { TagLexer } from "../../modules/lexer/TagLexer";
import { TagLexer, TagSubLexer } from "../../modules/lexer/TagLexer";
import { NodeTypes } from "../../modules/req/NodeTypes";
import { ReservedTags } from "concordialang-types/dist";

/**
* @author Thiago Delgado Pinto
@@ -36,7 +37,7 @@ describe( 'TagLexerTest', () => {
let names = lexer.analyze( line ).nodes.map( ( node ) => node.name );
expect( names ).toEqual( [ "hello", "world" ] );
} );

it( 'detects a tag with content', () => {
let line = '@hello( world )';
let r = lexer.analyze( line );
@@ -100,7 +101,23 @@ describe( 'TagLexerTest', () => {
expect( nodeOne.content ).toEqual( [ 'bar' ] );
let nodeTwo = r.nodes[ 1 ];
expect( nodeTwo.name ).toEqual( 'a' );
expect( nodeTwo.content ).toEqual( [ 'b', 'c' ] );
expect( nodeTwo.content ).toEqual( [ 'b', 'c' ] );
} );



it( 'detects subtypes', () => {

const l = new TagLexer( [
new TagSubLexer( ReservedTags.IGNORE, [ ReservedTags.IGNORE ] )
] );

const r = l.analyze( '@ignore' );
expect( r ).toBeDefined();
expect( r.errors ).toHaveLength( 0 );
expect( r.nodes ).toHaveLength( 1 );

expect( r.nodes[ 0 ].subType ).toEqual( ReservedTags.IGNORE );
} );

} );
@@ -1,7 +1,6 @@
import { join } from 'path';
import { FileInfo, Import, Location, Feature, Document, TestCase, Tag } from 'concordialang-types';
import { FileInfo, Import, Location, Feature, Document, TestCase, Tag, ReservedTags } from 'concordialang-types';
import { NodeTypes } from '../../modules/req/NodeTypes';
import { ReservedTags } from '../../modules/req/ReservedTags';
import { AugmentedSpec } from '../../modules/ast/AugmentedSpec';
import { TestCaseSSA } from '../../modules/semantic/TestCaseSSA';

@@ -103,7 +103,7 @@ describe( 'TCGenTest', () => {
]
);

expect( tc.shoudFail ).toBeFalsy();
expect( tc.shouldFail ).toBeFalsy();

} );

@@ -168,7 +168,7 @@ describe( 'TCGenTest', () => {
]
);

expect( tc.shoudFail ).toBeTruthy();
expect( tc.shouldFail ).toBeTruthy();

// ---

@@ -31,6 +31,8 @@
"tagImportance": [ "importance" ],
"tagIgnore": [ "ignore" ],
"tagGenerated": [ "generated" ],
"tagFail": [ "fail" ],
"tagGenerateOnlyValidValues": [ "generate-only-valid-values" ],

"language": [ "language" ],

@@ -31,6 +31,8 @@
"tagImportance": [ "importance" ],
"tagIgnore": [ "ignore" ],
"tagGenerated": [ "generated" ],
"tagFail": [ "fail" ],
"tagGenerateOnlyValidValues": [ "generate-only-valid-values" ],

"language": [ "language" ],

@@ -8,6 +8,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
});
};
Object.defineProperty(exports, "__esModule", { value: true });
const concordialang_types_1 = require("concordialang-types");
const PreTestCaseGenerator_1 = require("../testscenario/PreTestCaseGenerator");
const TSGen_1 = require("../testscenario/TSGen");
const VariantSelectionStrategy_1 = require("../selection/VariantSelectionStrategy");
@@ -20,7 +21,6 @@ const util_1 = require("util");
const RuntimeException_1 = require("../req/RuntimeException");
const fs_1 = require("fs");
const Defaults_1 = require("./Defaults");
const ReservedTags_1 = require("../req/ReservedTags");
const Warning_1 = require("../req/Warning");
const DataTestCaseMix_1 = require("../testcase/DataTestCaseMix");
class TCGenController {
@@ -154,7 +154,7 @@ class TCGenController {
case Defaults_1.VariantSelectionOptions.FIRST:
return new VariantSelectionStrategy_1.FirstVariantSelectionStrategy();
case Defaults_1.VariantSelectionOptions.FIRST_MOST_IMPORTANT:
return new VariantSelectionStrategy_1.FirstMostImportantVariantSelectionStrategy(options.importance, [ReservedTags_1.ReservedTags.IMPORTANCE]);
return new VariantSelectionStrategy_1.FirstMostImportantVariantSelectionStrategy(options.importance, [concordialang_types_1.ReservedTags.IMPORTANCE]);
case Defaults_1.VariantSelectionOptions.ALL:
return new VariantSelectionStrategy_1.AllVariantsSelectionStrategy();
default: {
@@ -38,6 +38,8 @@ class EnglishKeywordDictionary {
this.tagImportance = ['importance'];
this.tagIgnore = ['ignore'];
this.tagGenerated = ['generated'];
this.tagFail = ['fail'];
this.tagGenerateOnlyValidValues = ['generate-only-valid-values'];
// Also available in Gherkin
this.language = ['language'];
this.feature = ['feature', 'story', 'user story'];
@@ -1,5 +1,6 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const concordialang_types_1 = require("concordialang-types");
const VariantLexer_1 = require("./VariantLexer");
const TestEventLexer_1 = require("../lexer/TestEventLexer");
const DatabasePropertyLexer_1 = require("./DatabasePropertyLexer");
@@ -52,16 +53,28 @@ class Lexer {
this._lexers = [];
this._lexersMap = new Map(); // iterable in insertion order
this._lastLexer = null;
this._subLexers = [];
this._inLongString = false;
this._mustRecognizeAsText = false;
const dictionary = this.loadDictionary(_defaultLanguage); // may throw Error
if (!dictionary) {
throw new Error('Cannot load a dictionary for the language: ' + _defaultLanguage);
}
this._subLexers = [
new TagLexer_1.TagSubLexer(concordialang_types_1.ReservedTags.IGNORE, dictionary.tagIgnore),
new TagLexer_1.TagSubLexer(concordialang_types_1.ReservedTags.GENERATED, dictionary.tagGenerated),
new TagLexer_1.TagSubLexer(concordialang_types_1.ReservedTags.FAIL, dictionary.tagFail),
new TagLexer_1.TagSubLexer(concordialang_types_1.ReservedTags.SCENARIO, dictionary.tagScenario),
new TagLexer_1.TagSubLexer(concordialang_types_1.ReservedTags.VARIANT, dictionary.tagVariant),
new TagLexer_1.TagSubLexer(concordialang_types_1.ReservedTags.FEATURE, dictionary.tagFeature),
new TagLexer_1.TagSubLexer(concordialang_types_1.ReservedTags.GENERATE_ONLY_VALID_VALUES, dictionary.tagGenerateOnlyValidValues),
new TagLexer_1.TagSubLexer(concordialang_types_1.ReservedTags.IMPORTANCE, dictionary.tagImportance),
new TagLexer_1.TagSubLexer(concordialang_types_1.ReservedTags.GLOBAL, dictionary.tagGlobal)
];
this._lexers = [
new LongStringLexer_1.LongStringLexer(),
new LanguageLexer_1.LanguageLexer(dictionary.language),
new TagLexer_1.TagLexer(),
new TagLexer_1.TagLexer(this._subLexers),
new ImportLexer_1.ImportLexer(dictionary.import),
new FeatureLexer_1.FeatureLexer(dictionary.feature),
new BackgroundLexer_1.BackgroundLexer(dictionary.background),
@@ -160,7 +173,6 @@ class Lexer {
return false;
}
let result;
let node;
// Analyze with lexers of the suggested node types
if (this._lastLexer !== null) {
const suggestedNodeTypes = this._lastLexer.suggestedNextNodeTypes();
@@ -251,13 +263,12 @@ class Lexer {
|| {};
for (let lexer of this._lexers) {
if (this.isAWordBasedLexer(lexer)) {
let nodeType = lexer.affectedKeyword();
let words = dict[nodeType];
if (words) {
lexer.updateWords(words);
}
this.updateKeywordBasedLexer(lexer, dict);
}
}
for (let subLexer of this._subLexers) {
this.updateKeywordBasedLexer(subLexer, dict);
}
return dict;
}
/**
@@ -273,5 +284,12 @@ class Lexer {
isAWordBasedLexer(obj) {
return obj.updateWords !== undefined;
}
updateKeywordBasedLexer(kbl, dict) {
const nodeType = kbl.affectedKeyword();
const words = dict[nodeType];
if (words) {
kbl.updateWords(words);
}
}
}
exports.Lexer = Lexer;
@@ -11,13 +11,23 @@ const XRegExp = require('xregexp');
* @author Thiago Delgado Pinto
*/
class TagLexer {
constructor(_subLexers = []) {
this._subLexers = _subLexers;
}
/** @inheritDoc */
nodeType() {
return NodeTypes_1.NodeTypes.TAG;
}
/** @inheritDoc */
suggestedNextNodeTypes() {
return [NodeTypes_1.NodeTypes.TAG, NodeTypes_1.NodeTypes.VARIANT, NodeTypes_1.NodeTypes.FEATURE, NodeTypes_1.NodeTypes.SCENARIO];
return [
NodeTypes_1.NodeTypes.TAG,
NodeTypes_1.NodeTypes.VARIANT,
NodeTypes_1.NodeTypes.FEATURE,
NodeTypes_1.NodeTypes.SCENARIO,
NodeTypes_1.NodeTypes.UI_ELEMENT,
NodeTypes_1.NodeTypes.UI_PROPERTY
];
}
/** @inheritDoc */
analyze(line, lineNumber) {
@@ -67,9 +77,44 @@ class TagLexer {
name: result[1],
content: content
};
// Try to decide what subtype the tag has.
// An undefined subtype is valid and it means that the tag is not a reserved tag.
for (let subLexer of this._subLexers) {
if (subLexer.containsName(node.name)) {
node.subType = subLexer.affectedKeyword();
}
}
nodes.push(node);
}
return { nodes: nodes, errors: errors };
}
}
exports.TagLexer = TagLexer;
/**
* Allows to compare a tag name against a set of words in order to detect its subtype.
*
* @author Thiago Delgado Pinto
*/
class TagSubLexer {
constructor(_affectedKeyword, _words) {
this._affectedKeyword = _affectedKeyword;
this._words = _words;
}
/** @inheritDoc */
affectedKeyword() {
return this._affectedKeyword;
}
/** @inheritDoc */
updateWords(words) {
this._words = words.map(w => w.toLowerCase());
}
/**
* Compares if the tag's name is in the set of words.
*
* @param name Name to compare
*/
containsName(name) {
return this._words.indexOf(name.toLowerCase()) >= 0;
}
}
exports.TagSubLexer = TagSubLexer;
@@ -1,6 +1,6 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const SyntaticException_1 = require("../req/SyntaticException");
const SyntacticException_1 = require("../req/SyntacticException");
const TypeChecking_1 = require("../util/TypeChecking");
/**
* AfterAll parser
@@ -12,7 +12,7 @@ class AfterAllParser {
analyze(node, context, it, errors) {
// Check whether a similar node was already declared
if (TypeChecking_1.isDefined(context.doc.afterAll)) {
let e = new SyntaticException_1.SyntaticException('Event already declared: After All', node.location);
let e = new SyntacticException_1.SyntacticException('Event already declared: After All', node.location);
errors.push(e);
return false;
}
@@ -1,6 +1,6 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const SyntaticException_1 = require("../req/SyntaticException");
const SyntacticException_1 = require("../req/SyntacticException");
const TypeChecking_1 = require("../util/TypeChecking");
/**
* AfterEachScenario parser
@@ -12,13 +12,13 @@ class AfterEachScenarioParser {
analyze(node, context, it, errors) {
// Check whether a Feature was declared
if (!context.doc.feature) {
let e = new SyntaticException_1.SyntaticException('The event After Each Scenario must be declared after a Feature', node.location);
let e = new SyntacticException_1.SyntacticException('The event After Each Scenario must be declared after a Feature', node.location);
errors.push(e);
return false;
}
// Check whether a similar node was already declared
if (TypeChecking_1.isDefined(context.doc.afterEachScenario)) {
let e = new SyntaticException_1.SyntaticException('Event already declared: After Each Scenario', node.location);
let e = new SyntacticException_1.SyntacticException('Event already declared: After Each Scenario', node.location);
errors.push(e);
return false;
}
@@ -1,6 +1,6 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const SyntaticException_1 = require("../req/SyntaticException");
const SyntacticException_1 = require("../req/SyntacticException");
const TypeChecking_1 = require("../util/TypeChecking");
/**
* AfterFeature parser
@@ -12,13 +12,13 @@ class AfterFeatureParser {
analyze(node, context, it, errors) {
// Check whether a Feature was declared
if (!context.doc.feature) {
let e = new SyntaticException_1.SyntaticException('The event After Feature must be declared after a Feature', node.location);
let e = new SyntacticException_1.SyntacticException('The event After Feature must be declared after a Feature', node.location);
errors.push(e);
return false;
}
// Check whether a similar node was already declared
if (TypeChecking_1.isDefined(context.doc.afterFeature)) {
let e = new SyntaticException_1.SyntaticException('Event already declared: After Feature', node.location);
let e = new SyntacticException_1.SyntacticException('Event already declared: After Feature', node.location);
errors.push(e);
return false;
}
@@ -1,6 +1,6 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const SyntaticException_1 = require("../req/SyntaticException");
const SyntacticException_1 = require("../req/SyntacticException");
const TypeChecking_1 = require("../util/TypeChecking");
/**
* Background parser
@@ -12,18 +12,18 @@ class BackgroundParser {
analyze(node, context, it, errors) {
// Checks if a feature has been declared before it
if (!context.doc.feature) {
let e = new SyntaticException_1.SyntaticException('A background must be declared after a feature.', node.location);
let e = new SyntacticException_1.SyntacticException('A background must be declared after a feature.', node.location);
errors.push(e);
return false;
}
let feature = context.doc.feature;
if (feature.background) {
let e = new SyntaticException_1.SyntaticException('A feature cannot have more than one background.', node.location);
let e = new SyntacticException_1.SyntacticException('A feature cannot have more than one background.', node.location);
errors.push(e);
return false;
}
if (TypeChecking_1.isDefined(feature.scenarios) && feature.scenarios.length > 0) {
let e = new SyntaticException_1.SyntaticException('A background must be declared before a scenario.', node.location);
let e = new SyntacticException_1.SyntacticException('A background must be declared before a scenario.', node.location);
errors.push(e);
return false;
}
@@ -1,6 +1,6 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const SyntaticException_1 = require("../req/SyntaticException");
const SyntacticException_1 = require("../req/SyntacticException");
const TypeChecking_1 = require("../util/TypeChecking");
/**
* BeforeAll parser
@@ -12,7 +12,7 @@ class BeforeAllParser {
analyze(node, context, it, errors) {
// Check whether a similar node was already declared
if (TypeChecking_1.isDefined(context.doc.beforeAll)) {
let e = new SyntaticException_1.SyntaticException('Event already declared: Before All', node.location);
let e = new SyntacticException_1.SyntacticException('Event already declared: Before All', node.location);
errors.push(e);
return false;
}

0 comments on commit 616355b

Please sign in to comment.
You can’t perform that action at this time.