odatafy-parser
Version:
generate odatafy ast from odata query parameters
496 lines (495 loc) • 20.5 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const assert_1 = __importDefault(require("assert"));
const filterExpressionPreProc_1 = require("../../src/processing/filterExpressionPreProc");
//tests if result conforms to given format via regexp
const Str_Escape_Regex = /\$(.*?)\$/;
const Func_Escape_Regex = /\%(.*?)\%/;
const Expr_Escape_Regex = /\§(.*?)\§/;
const Multiexpr_Escape_Regex = /\&(.*?)\&/;
describe('expressionPreProcessingFilter tests', () => {
describe('test getIdentifier()', () => {
[{
escapeType: 'String',
input: filterExpressionPreProc_1.Prefixes.Str_Escape,
expectedRegex: Str_Escape_Regex,
expectedLength: 42
},
{
escapeType: 'Function',
input: filterExpressionPreProc_1.Prefixes.Func_Escape,
expectedRegex: Func_Escape_Regex,
expectedLength: 42
},
{
escapeType: 'Expression',
input: filterExpressionPreProc_1.Prefixes.Expr_Escape,
expectedRegex: Expr_Escape_Regex,
expectedLength: 42
},
{
escapeType: 'Multiexpression',
input: filterExpressionPreProc_1.Prefixes.Multiexpr_Escape,
expectedRegex: Multiexpr_Escape_Regex,
expectedLength: 42
}].forEach(testcase => {
it(`should generate a valid ${testcase.escapeType} Escape Identifier`, () => {
let identifier = (0, filterExpressionPreProc_1.getIdentifier)(testcase.input);
(0, assert_1.default)(testcase.expectedRegex.test(identifier));
(0, assert_1.default)(identifier.length == testcase.expectedLength);
});
});
});
describe('escapeStrings()', () => {
[{
type: "no strings",
input: "Alter eq 5",
expectedRegex: /Alter eq 5/,
expectedToBeEscapeds: []
},
{
type: "simple string",
input: "'HelloWorld'",
expectedRegex: /\$(.*?)\$/,
expectedToBeEscapeds: [
"'HelloWorld'"
]
},
{
type: "string in an expression",
input: "Name eq 'Mustermann'",
expectedRegex: /Name eq \$(.*?)\$/,
expectedToBeEscapeds: [
"'Mustermann'"
]
},
{
type: "string in a function",
input: "contains(Name, 'Muster')",
expectedRegex: /contains\(Name, \$(.*?)\$/,
expectedToBeEscapeds: [
"'Muster'"
]
},
{
type: "multiple strings in an expression",
input: "Name eq 'Mustermann' and Vorname eq 'Max'",
expectedRegex: /Name eq \$(.*?)\$ and Vorname eq \$(.*?)\$/,
expectedToBeEscapeds: [
"'Mustermann'",
"'Max'"
]
}].forEach(testcase => {
let [resultString, resultRecord] = (0, filterExpressionPreProc_1.escapeStrings)(testcase.input);
it(`should escape a ${testcase.type} ("${testcase.input}") and return a correct result string`, () => {
//test that the right result string is returned
(0, assert_1.default)(testcase.expectedRegex.test(resultString));
});
it(`should escape a ${testcase.type} ("${testcase.input}") and return a resolver with valid keys`, () => {
//test that all the result resolver keys are escape identifiers
Object.keys(resultRecord).forEach(key => {
(0, assert_1.default)(Str_Escape_Regex.test(key), `key ${key} is not a valid string escape identifier`);
});
});
it(`should escape a ${testcase.type} ("${testcase.input}") and return a resolver containing all expectedToBeEscapeds`, () => {
//test that the resolver contains all of the expected escape sequences
testcase.expectedToBeEscapeds.forEach(toBeEscaped => {
(0, assert_1.default)(Object.values(resultRecord).includes(toBeEscaped), `escaped sequence ${toBeEscaped} is missing in the resolver`);
});
});
});
});
describe('escapeFunctions()', () => {
[{
type: "no functions",
input: "Alter eq 5",
expectedRegex: /Alter eq 5/,
expectedToBeEscapeds: []
},
//two arg functions
//"concat" / "contains" / "endswith" / "indexof" / "matchesPattern" / "startswith" / "geo.distance" / "geo.intersects" / "hassubset" / "hassubsequence"
{
type: "simple contains function",
input: "contains(Name, $abcdabcdabcdabcdabcdabcdabcdabcdabcdabcd$)",
expectedRegex: /\%(.*?)\%/,
expectedToBeEscapeds: [
"contains(Name, $abcdabcdabcdabcdabcdabcdabcdabcdabcdabcd$)"
]
},
{
type: "simple concat function",
input: "concat(Name, $abcdabcdabcdabcdabcdabcdabcdabcdabcdabcd$)",
expectedRegex: /\%(.*?)\%/,
expectedToBeEscapeds: [
"concat(Name, $abcdabcdabcdabcdabcdabcdabcdabcdabcdabcd$)"
]
},
{
type: "simple endswith function",
input: "endswith(Name, $abcdabcdabcdabcdabcdabcdabcdabcdabcdabcd$)",
expectedRegex: /\%(.*?)\%/,
expectedToBeEscapeds: [
"endswith(Name, $abcdabcdabcdabcdabcdabcdabcdabcdabcdabcd$)"
]
},
{
type: "simple startswith function",
input: "startswith(Name, $abcdabcdabcdabcdabcdabcdabcdabcdabcdabcd$)",
expectedRegex: /\%(.*?)\%/,
expectedToBeEscapeds: [
"startswith(Name, $abcdabcdabcdabcdabcdabcdabcdabcdabcdabcd$)"
]
},
{
type: "simple geo.distance function",
input: "geo.distance(Location, $abcdabcdabcdabcdabcdabcdabcdabcdabcdabcd$)",
expectedRegex: /\%(.*?)\%/,
expectedToBeEscapeds: [
"geo.distance(Location, $abcdabcdabcdabcdabcdabcdabcdabcdabcdabcd$)"
]
},
{
type: "simple geo.intersects function",
input: "geo.intersects(Location, $abcdabcdabcdabcdabcdabcdabcdabcdabcdabcd$)",
expectedRegex: /\%(.*?)\%/,
expectedToBeEscapeds: [
"geo.intersects(Location, $abcdabcdabcdabcdabcdabcdabcdabcdabcdabcd$)"
]
},
{
type: "simple hassubset function",
input: "hassubset(Name, $abcdabcdabcdabcdabcdabcdabcdabcdabcdabcd$)",
expectedRegex: /\%(.*?)\%/,
expectedToBeEscapeds: [
"hassubset(Name, $abcdabcdabcdabcdabcdabcdabcdabcdabcdabcd$)"
]
},
{
type: "simple hassubsequence function",
input: "hassubsequence(Name, $abcdabcdabcdabcdabcdabcdabcdabcdabcdabcd$)",
expectedRegex: /\%(.*?)\%/,
expectedToBeEscapeds: [
"hassubsequence(Name, $abcdabcdabcdabcdabcdabcdabcdabcdabcdabcd$)"
]
},
{
type: "simple indexof function",
input: "indexof(Name, $abcdabcdabcdabcdabcdabcdabcdabcdabcdabcd$)",
expectedRegex: /\%(.*?)\%/,
expectedToBeEscapeds: [
"indexof(Name, $abcdabcdabcdabcdabcdabcdabcdabcdabcdabcd$)"
]
},
{
type: "simple matchesPattern function",
input: "matchesPattern(Name, $abcdabcdabcdabcdabcdabcdabcdabcdabcdabcd$)",
expectedRegex: /\%(.*?)\%/,
expectedToBeEscapeds: [
"matchesPattern(Name, $abcdabcdabcdabcdabcdabcdabcdabcdabcdabcd$)"
]
},
//one arg functions
//"length" / "tolower"/"toupper"/"trim"/"year"/"month"/"day"/"hour"/"minute"/"second"/"fractionalseconds"/"totalseconds"/"date"/"time"/"totaloffsetminutes"/"round"/"floor"/"ceiling"/"geo.length"
{
type: "simple length function",
input: "length($abcdabcdabcdabcdabcdabcdabcdabcdabcdabcd$)",
expectedRegex: /\%(.*?)\%/,
expectedToBeEscapeds: [
"length($abcdabcdabcdabcdabcdabcdabcdabcdabcdabcd$)"
]
},
{
type: "simple tolower function",
input: "tolower($abcdabcdabcdabcdabcdabcdabcdabcdabcdabcd$)",
expectedRegex: /\%(.*?)\%/,
expectedToBeEscapeds: [
"tolower($abcdabcdabcdabcdabcdabcdabcdabcdabcdabcd$)"
]
},
{
type: "simple toupper function",
input: "toupper($abcdabcdabcdabcdabcdabcdabcdabcdabcdabcd$)",
expectedRegex: /\%(.*?)\%/,
expectedToBeEscapeds: [
"toupper($abcdabcdabcdabcdabcdabcdabcdabcdabcdabcd$)"
]
},
{
type: "simple trim function",
input: "trim($abcdabcdabcdabcdabcdabcdabcdabcdabcdabcd$)",
expectedRegex: /\%(.*?)\%/,
expectedToBeEscapeds: [
"trim($abcdabcdabcdabcdabcdabcdabcdabcdabcdabcd$)"
]
},
{
type: "simple year function",
input: "year(StartTime)",
expectedRegex: /\%(.*?)\%/,
expectedToBeEscapeds: [
"year(StartTime)"
]
},
{
type: "simple month function",
input: "month(StartTime)",
expectedRegex: /\%(.*?)\%/,
expectedToBeEscapeds: [
"month(StartTime)"
]
},
{
type: "simple day function",
input: "day(StartTime)",
expectedRegex: /\%(.*?)\%/,
expectedToBeEscapeds: [
"day(StartTime)"
]
},
{
type: "simple hour function",
input: "hour(StartTime)",
expectedRegex: /\%(.*?)\%/,
expectedToBeEscapeds: [
"hour(StartTime)"
]
},
{
type: "simple minute function",
input: "minute(StartTime)",
expectedRegex: /\%(.*?)\%/,
expectedToBeEscapeds: [
"minute(StartTime)"
]
},
{
type: "simple second function",
input: "second(StartTime)",
expectedRegex: /\%(.*?)\%/,
expectedToBeEscapeds: [
"second(StartTime)"
]
},
{
type: "simple fractionalseconds function",
input: "fractionalseconds(StartTime)",
expectedRegex: /\%(.*?)\%/,
expectedToBeEscapeds: [
"fractionalseconds(StartTime)"
]
},
{
type: "simple totalseconds function",
input: "totalseconds(StartTime)",
expectedRegex: /\%(.*?)\%/,
expectedToBeEscapeds: [
"totalseconds(StartTime)"
]
},
{
type: "simple date function",
input: "date(StartTime)",
expectedRegex: /\%(.*?)\%/,
expectedToBeEscapeds: [
"date(StartTime)"
]
},
{
type: "simple time function",
input: "time(StartTime)",
expectedRegex: /\%(.*?)\%/,
expectedToBeEscapeds: [
"time(StartTime)"
]
},
{
type: "simple totaloffsetminutes function",
input: "totaloffsetminutes(StartTime)",
expectedRegex: /\%(.*?)\%/,
expectedToBeEscapeds: [
"totaloffsetminutes(StartTime)"
]
},
{
type: "simple round function",
input: "round(1.5)",
expectedRegex: /\%(.*?)\%/,
expectedToBeEscapeds: [
"round(1.5)"
]
},
{
type: "simple floor function",
input: "floor(1.5)",
expectedRegex: /\%(.*?)\%/,
expectedToBeEscapeds: [
"floor(1.5)"
]
},
{
type: "simple ceiling function",
input: "ceiling(1.5)",
expectedRegex: /\%(.*?)\%/,
expectedToBeEscapeds: [
"ceiling(1.5)"
]
},
{
type: "simple geo.length function",
input: "geo.length(Location)",
expectedRegex: /\%(.*?)\%/,
expectedToBeEscapeds: [
"geo.length(Location)"
]
},
//zero arg functions
//"mindatetime" / "maxdatetime" / "now"
{
type: "simple mindatetime function",
input: "mindatetime()",
expectedRegex: /\%(.*?)\%/,
expectedToBeEscapeds: [
"mindatetime()"
]
},
{
type: "simple maxdatetime function",
input: "maxdatetime()",
expectedRegex: /\%(.*?)\%/,
expectedToBeEscapeds: [
"maxdatetime()"
]
},
{
type: "simple now function",
input: "now()",
expectedRegex: /\%(.*?)\%/,
expectedToBeEscapeds: [
"now()"
]
},
//others
{
type: "function in an expression",
input: "Alter eq 18 and contains(Name, $abcdabcdabcdabcdabcdabcdabcdabcdabcdabcd$)",
expectedRegex: /Alter eq 18 and \%(.*?)\%/,
expectedToBeEscapeds: [
"contains(Name, $abcdabcdabcdabcdabcdabcdabcdabcdabcdabcd$)"
]
},
{
type: "function in a function",
input: "contains(Name, concat($abcdabcdabcdabcdabcdabcdabcdabcdabcdabcd$, $abcdabcdabcdabcdabcdabcdabcdabcdabcd1234$))",
expectedRegex: /\%(.*?)\%/,
expectedToBeEscapeds: [
"contains(Name, concat($abcdabcdabcdabcdabcdabcdabcdabcdabcdabcd$, $abcdabcdabcdabcdabcdabcdabcdabcdabcd1234$))"
]
},
{
type: "multiple functions in an expression",
input: "contains(Name, $abcdabcdabcdabcdabcdabcdabcdabcdabcdabcd$) and contains(Vorname, $abcdabcdabcdabcdabcdabcdabcdabcdabcd1234$)",
expectedRegex: /\%(.*?)\% and \%(.*?)\%/,
expectedToBeEscapeds: [
"contains(Name, $abcdabcdabcdabcdabcdabcdabcdabcdabcdabcd$)",
"contains(Vorname, $abcdabcdabcdabcdabcdabcdabcdabcdabcd1234$)"
]
}].forEach(testcase => {
let [resultString, resultRecord] = (0, filterExpressionPreProc_1.escapeFunctions)(testcase.input);
it(`should escape a ${testcase.type} ("${testcase.input}")`, () => {
//test that the right result string is returned
(0, assert_1.default)(testcase.expectedRegex.test(resultString), `expected ${testcase.expectedRegex} but got ${resultString}`);
//test that all the result resolver keys are escape identifiers
Object.keys(resultRecord).forEach(key => {
(0, assert_1.default)(Func_Escape_Regex.test(key), `key ${key} is not a valid function escape identifier`);
});
//test that the resolver contains all of the expected escape sequences
testcase.expectedToBeEscapeds.forEach(toBeEscaped => {
(0, assert_1.default)(Object.values(resultRecord).includes(toBeEscaped), `escaped sequence ${toBeEscaped} is missing in the resolver`);
});
});
});
});
describe('hasOnlyMatchingParentheses()', () => {
[{
input: '()',
expected: true
},
{
input: '(())',
expected: true
},
{
input: '()()',
expected: true
},
{
input: '()(())',
expected: true
},
{
input: '(',
expected: false
},
{
input: '())',
expected: false
},
{
input: '(()',
expected: false
},
{
input: '()(()',
expected: false
}].forEach(testcase => {
it(`should return ${testcase.expected} for expression ${testcase.input}`, () => {
assert_1.default.equal((0, filterExpressionPreProc_1.hasOnlyMatchingParentheses)(testcase.input), testcase.expected);
});
});
});
describe('reverseExprLogic()', () => {
[{
input: "A eq 1 and B eq 2 and C eq 3",
expected: "C eq 3 and B eq 2 and A eq 1"
},
{
input: "A eq 1 or B eq 2 or C eq 3",
expected: "C eq 3 or B eq 2 or A eq 1"
},
{
input: "A eq 1 and B eq 2 or C eq 3",
expected: "C eq 3 or B eq 2 and A eq 1"
},
{
input: "A eq 'Fynn' and B eq 'Steffen' or C eq 'Robin'",
expected: "C eq 'Robin' or B eq 'Steffen' and A eq 'Fynn'"
},
{
input: "(A eq 'Fynn' and B eq 'Steffen') or C eq 'Robin'",
expected: "C eq 'Robin' or (B eq 'Steffen' and A eq 'Fynn')"
},
{
input: "A eq 'Fynn' and (B eq 'Steffen' or C eq 'Robin')",
expected: "(C eq 'Robin' or B eq 'Steffen') and A eq 'Fynn'"
},
{
input: "A eq 'Fynn' and (B eq 'Steffen' or C eq 'Robin' and D eq 'Maik')",
expected: "(D eq 'Maik' and C eq 'Robin' or B eq 'Steffen') and A eq 'Fynn'"
},
{
input: "A eq 'Fynn' and not (B eq 'Steffen' or C eq 'Robin' and D eq 'Maik')",
expected: "not (D eq 'Maik' and C eq 'Robin' or B eq 'Steffen') and A eq 'Fynn'"
},
{
input: "A eq lowercase('Fynn') and not (B eq 'Steffen' or C eq 'Robin' and D eq 'Maik')",
expected: "not (D eq 'Maik' and C eq 'Robin' or B eq 'Steffen') and A eq lowercase('Fynn')"
}].forEach(testcase => {
it(`should return ${testcase.expected} for expression ${testcase.input}`, () => {
assert_1.default.equal((0, filterExpressionPreProc_1.reverseExprLogic)(testcase.input), testcase.expected);
});
});
});
});