Skip to content

Commit

Permalink
Merge pull request #561 from GuillaumeGomez/command-input-validator
Browse files Browse the repository at this point in the history
Command input validator - part 2
  • Loading branch information
GuillaumeGomez authored Feb 23, 2024
2 parents 4030f3b + e56902e commit af94218
Show file tree
Hide file tree
Showing 24 changed files with 131 additions and 73 deletions.
95 changes: 46 additions & 49 deletions src/commands/assert.js
Original file line number Diff line number Diff line change
Expand Up @@ -478,43 +478,51 @@ function parseAssertPropertyFalse(parser) {
}

function parseAssertAttributeInner(parser, assertFalse) {
const err = 'Read the documentation to see the accepted inputs';
const elems = parser.elems;
const identifiers = ['ALL', 'CONTAINS', 'STARTS_WITH', 'ENDS_WITH', 'NEAR'];
const identifiers = ['CONTAINS', 'ENDS_WITH', 'STARTS_WITH', 'NEAR', 'ALL'];
const jsonValidator = {
kind: 'json',
keyTypes: {
'string': [],
},
valueTypes: {
'string': [], 'number': [], 'ident': ['null'],
},
};
const ret = validator(parser,
{
kind: 'tuple',
elements: [
{ kind: 'selector' },
jsonValidator,
{
kind: 'ident',
allowed: identifiers,
optional: true,
alternatives: [
{
kind: 'array',
valueTypes: {
'ident': identifiers,
},
},
],
},
],
},
);
if (ret.error !== undefined) {
return ret;
}

const tuple = ret.value;
const warnings = [];
const enabledChecks = Object.create(null);
const enabledChecks = new Set();

if (elems.length === 0) {
return {
'error': 'expected a tuple, found nothing. ' + err,
};
} else if (elems.length !== 1 || elems[0].kind !== 'tuple') {
return {'error': `expected a tuple, found \`${parser.getRawArgs()}\`. ${err}`};
}
const tuple = elems[0].getRaw();
if (tuple.length < 2 || tuple.length > 3) {
return {
'error': 'invalid number of values in the tuple (expected 2 or 3, found ' +
tuple.length + '), ' + err,
};
} else if (tuple[0].kind !== 'string') {
return {
'error': 'expected a CSS selector or an XPath as first argument, ' +
`found ${tuple[0].getArticleKind()}`,
};
} else if (tuple[1].kind !== 'json') {
return {
'error': 'expected a JSON dictionary as second argument, found ' +
`\`${tuple[1].getErrorText()}\` (${tuple[1].getArticleKind()})`,
};
} else if (tuple.length === 3) {
const ret = fillEnabledChecks(tuple[2], identifiers, enabledChecks, warnings, 'third');
if (ret !== null) {
return ret;
}
if (tuple.length > 2) {
fillEnabledChecksV2(tuple[2], enabledChecks, warnings, 'third');
}

const selector = tuple[0].getSelector();
const selector = tuple[0].value;
const xpath = selector.isXPath ? 'XPath ' : 'selector ';

const varName = 'parseAssertElemAttr';
Expand All @@ -525,17 +533,8 @@ function parseAssertAttributeInner(parser, assertFalse) {
const { checks, hasSpecialChecks } = makeExtendedChecks(
enabledChecks, assertFalse, 'nonMatchingAttrs', 'attribute', 'attr', varKey, varValue);

const json = tuple[1].getRaw();
const entries = validateJson(
json,
{'string': [], 'number': [], 'ident': ['null']},
'attribute',
);
if (entries.error !== undefined) {
return entries;
}
const json = tuple[1].value;
const isPseudo = !selector.isXPath && selector.pseudo !== null;
warnings.push(...entries.warnings);
if (isPseudo) {
warnings.push(`Pseudo-elements (\`${selector.pseudo}\`) don't have attributes so \
the check will be performed on the element itself`);
Expand All @@ -544,7 +543,7 @@ the check will be performed on the element itself`);
// JSON.stringify produces a problematic output so instead we use this.
const tests = [];
const nullAttributes = [];
for (const [k, v] of Object.entries(entries.values)) {
for (const [k, v] of json) {
if (v.kind !== 'ident') {
tests.push(`"${k}":"${v.value}"`);
} else {
Expand All @@ -553,10 +552,8 @@ the check will be performed on the element itself`);
}

if (nullAttributes.length > 0 && hasSpecialChecks) {
const k = Object.entries(enabledChecks)
.filter(([k, v]) => v && k !== 'ALL')
.map(([k, _]) => k);
warnings.push(`Special checks (${k.join(', ')}) will be ignored for \`null\``);
const k = [...enabledChecks].filter(k => k !== 'ALL').join(', ');
warnings.push(`Special checks (${k}) will be ignored for \`null\``);
}

let noAttrError = '';
Expand Down Expand Up @@ -594,7 +591,7 @@ if (nonMatchingAttrs.length !== 0) {
}`;

let instructions;
if (enabledChecks['ALL'] === true) {
if (enabledChecks.has('ALL')) {
instructions = `\
${getAndSetElements(selector, varName, true)}
for (let i = 0, len = ${varName}.length; i < len; ++i) {
Expand Down
9 changes: 7 additions & 2 deletions src/validator.js
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ function validateIdent(parser, allowedSyntax, validator) {
} else if (!allowedSyntax.allowed.includes(parser.value)) {
return validator.makeError(
`unexpected ${parser.kind} \`${parser.getErrorText()}\`. Allowed ${parser.kind}s are: \
[${allowedSyntax.allowed.map(v => `\`${v}\``).join(', ')}]`,
${listValues(allowedSyntax.allowed)}`,
);
}
return parser;
Expand Down Expand Up @@ -294,7 +294,7 @@ this JSON dict, allowed types are: ${Object.keys(allowedSyntax.valueTypes).join(
} else if (allowedForValue.length !== 0 && !allowedForValue.includes(value.value)) {
return validator.makeError(
`unexpected ${value.kind} \`${value.getErrorText()}\`. Allowed ${value.kind}s are: \
[${allowedForValue.map(v => `\`${v}\``).join(', ')}]`,
${listValues(allowedForValue)}`,
);
}
entries.set(key_s, {
Expand All @@ -305,6 +305,11 @@ this JSON dict, allowed types are: ${Object.keys(allowedSyntax.valueTypes).join(
return entries;
}

function listValues(values) {
values.sort();
return `[${values.map(v => `\`${v}\``).join(', ')}]`;
}

function isObject(obj) {
return typeof obj === 'object' && !Array.isArray(obj) && obj !== null;
}
Expand Down
6 changes: 5 additions & 1 deletion tests/test-js/api-output/parseAssertAttribute/err-1.toml
Original file line number Diff line number Diff line change
@@ -1 +1,5 @@
error = """expected a JSON dictionary as second argument, found `\"b\"` (a string)"""
level = 1
error = """expected second element of the tuple to be a JSON dict, found `\"b\"` (a string)"""
path = [
]
typeError = false
6 changes: 5 additions & 1 deletion tests/test-js/api-output/parseAssertAttribute/err-2.toml
Original file line number Diff line number Diff line change
@@ -1 +1,5 @@
error = """expected a JSON dictionary as second argument, found `\"b\"` (a string)"""
level = 1
error = """expected second element of the tuple to be a JSON dict, found `\"b\"` (a string)"""
path = [
]
typeError = false
6 changes: 5 additions & 1 deletion tests/test-js/api-output/parseAssertAttribute/err-5.toml
Original file line number Diff line number Diff line change
@@ -1 +1,5 @@
error = """expected a JSON dictionary as second argument, found `\"b\"` (a string)"""
level = 1
error = """expected second element of the tuple to be a JSON dict, found `\"b\"` (a string)"""
path = [
]
typeError = false
6 changes: 5 additions & 1 deletion tests/test-js/api-output/parseAssertAttribute/err-6.toml
Original file line number Diff line number Diff line change
@@ -1 +1,5 @@
error = """unknown identifier `all`. Available identifiers are: [`ALL`, `CONTAINS`, `STARTS_WITH`, `ENDS_WITH`, `NEAR`]"""
level = 2
error = """unexpected ident `all`. Allowed idents are: [`ALL`, `CONTAINS`, `ENDS_WITH`, `NEAR`, `STARTS_WITH`]"""
path = [
]
typeError = false
6 changes: 5 additions & 1 deletion tests/test-js/api-output/parseAssertAttribute/err-7.toml
Original file line number Diff line number Diff line change
@@ -1 +1,5 @@
error = """unknown identifier `ALLO`. Available identifiers are: [`ALL`, `CONTAINS`, `STARTS_WITH`, `ENDS_WITH`, `NEAR`]"""
level = 2
error = """unexpected ident `ALLO`. Allowed idents are: [`ALL`, `CONTAINS`, `ENDS_WITH`, `NEAR`, `STARTS_WITH`]"""
path = [
]
typeError = false
6 changes: 5 additions & 1 deletion tests/test-js/api-output/parseAssertAttribute/err-8.toml
Original file line number Diff line number Diff line change
@@ -1 +1,5 @@
error = """attribute `b` is duplicated"""
level = 2
error = """`b` key is duplicated in JSON dict"""
path = [
]
typeError = false
Original file line number Diff line number Diff line change
@@ -1 +1,5 @@
error = """unknown identifier `ALLO`. Available identifiers are: [`ALL`, `CONTAINS`, `STARTS_WITH`, `ENDS_WITH`, `NEAR`]"""
level = 2
error = """unexpected ident `ALLO`. Allowed idents are: [`ALL`, `CONTAINS`, `ENDS_WITH`, `NEAR`, `STARTS_WITH`]"""
path = [
]
typeError = false
Original file line number Diff line number Diff line change
@@ -1 +1,5 @@
error = """expected a JSON dictionary as second argument, found `\"b\"` (a string)"""
level = 1
error = """expected second element of the tuple to be a JSON dict, found `\"b\"` (a string)"""
path = [
]
typeError = false
Original file line number Diff line number Diff line change
@@ -1 +1,5 @@
error = """expected a JSON dictionary as second argument, found `\"b\"` (a string)"""
level = 1
error = """expected second element of the tuple to be a JSON dict, found `\"b\"` (a string)"""
path = [
]
typeError = false
Original file line number Diff line number Diff line change
@@ -1 +1,5 @@
error = """expected a JSON dictionary as second argument, found `\"b\"` (a string)"""
level = 1
error = """expected second element of the tuple to be a JSON dict, found `\"b\"` (a string)"""
path = [
]
typeError = false
Original file line number Diff line number Diff line change
@@ -1 +1,5 @@
error = """unknown identifier `all`. Available identifiers are: [`ALL`, `CONTAINS`, `STARTS_WITH`, `ENDS_WITH`, `NEAR`]"""
level = 2
error = """unexpected ident `all`. Allowed idents are: [`ALL`, `CONTAINS`, `ENDS_WITH`, `NEAR`, `STARTS_WITH`]"""
path = [
]
typeError = false
Original file line number Diff line number Diff line change
@@ -1 +1,5 @@
error = """unknown identifier `ALLO`. Available identifiers are: [`ALL`, `CONTAINS`, `STARTS_WITH`, `ENDS_WITH`, `NEAR`]"""
level = 2
error = """unexpected ident `ALLO`. Allowed idents are: [`ALL`, `CONTAINS`, `ENDS_WITH`, `NEAR`, `STARTS_WITH`]"""
path = [
]
typeError = false
Original file line number Diff line number Diff line change
@@ -1 +1,5 @@
error = """attribute `b` is duplicated"""
level = 2
error = """`b` key is duplicated in JSON dict"""
path = [
]
typeError = false
Original file line number Diff line number Diff line change
@@ -1 +1,5 @@
error = """unknown identifier `ALLO`. Available identifiers are: [`ALL`, `CONTAINS`, `STARTS_WITH`, `ENDS_WITH`, `NEAR`]"""
level = 2
error = """unexpected ident `ALLO`. Allowed idents are: [`ALL`, `CONTAINS`, `ENDS_WITH`, `NEAR`, `STARTS_WITH`]"""
path = [
]
typeError = false
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
level = 2
error = """unexpected ident `all`. Allowed idents are: [`CONTAINS`, `ENDS_WITH`, `STARTS_WITH`, `NEAR`]"""
error = """unexpected ident `all`. Allowed idents are: [`CONTAINS`, `ENDS_WITH`, `NEAR`, `STARTS_WITH`]"""
path = [
]
typeError = false
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
level = 2
error = """unexpected ident `all`. Allowed idents are: [`CONTAINS`, `ENDS_WITH`, `STARTS_WITH`, `NEAR`]"""
error = """unexpected ident `all`. Allowed idents are: [`CONTAINS`, `ENDS_WITH`, `NEAR`, `STARTS_WITH`]"""
path = [
]
typeError = false
2 changes: 1 addition & 1 deletion tests/test-js/api-output/parseAssertProperty/err-6.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
level = 2
error = """unexpected ident `all`. Allowed idents are: [`CONTAINS`, `ENDS_WITH`, `STARTS_WITH`, `NEAR`, `ALL`]"""
error = """unexpected ident `all`. Allowed idents are: [`ALL`, `CONTAINS`, `ENDS_WITH`, `NEAR`, `STARTS_WITH`]"""
path = [
]
typeError = false
2 changes: 1 addition & 1 deletion tests/test-js/api-output/parseAssertProperty/err-7.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
level = 2
error = """unexpected ident `ALLO`. Allowed idents are: [`CONTAINS`, `ENDS_WITH`, `STARTS_WITH`, `NEAR`, `ALL`]"""
error = """unexpected ident `ALLO`. Allowed idents are: [`ALL`, `CONTAINS`, `ENDS_WITH`, `NEAR`, `STARTS_WITH`]"""
path = [
]
typeError = false
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
level = 2
error = """unexpected ident `all`. Allowed idents are: [`CONTAINS`, `ENDS_WITH`, `STARTS_WITH`, `NEAR`, `ALL`]"""
error = """unexpected ident `all`. Allowed idents are: [`ALL`, `CONTAINS`, `ENDS_WITH`, `NEAR`, `STARTS_WITH`]"""
path = [
]
typeError = false
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
level = 2
error = """unexpected ident `ALLO`. Allowed idents are: [`CONTAINS`, `ENDS_WITH`, `STARTS_WITH`, `NEAR`, `ALL`]"""
error = """unexpected ident `ALLO`. Allowed idents are: [`ALL`, `CONTAINS`, `ENDS_WITH`, `NEAR`, `STARTS_WITH`]"""
path = [
]
typeError = false
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
level = 2
error = """unexpected ident `all`. Allowed idents are: [`CONTAINS`, `ENDS_WITH`, `STARTS_WITH`, `NEAR`]"""
error = """unexpected ident `all`. Allowed idents are: [`CONTAINS`, `ENDS_WITH`, `NEAR`, `STARTS_WITH`]"""
path = [
]
typeError = false
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
level = 2
error = """unexpected ident `all`. Allowed idents are: [`CONTAINS`, `ENDS_WITH`, `STARTS_WITH`, `NEAR`]"""
error = """unexpected ident `all`. Allowed idents are: [`CONTAINS`, `ENDS_WITH`, `NEAR`, `STARTS_WITH`]"""
path = [
]
typeError = false

0 comments on commit af94218

Please sign in to comment.