swift-pattern-compiler
Version:
A compiler which transforms SWIFT patterns to an object representation with additional information's.
756 lines (748 loc) • 25.8 kB
text/typescript
import * as test from "tape";
import { generator, getCharClass, getQuantifier } from "../src/generator";
import { ENodeType } from "../src/interfaces";
import { ITest } from "./testInterfaces";
test("objectGenerator module", t => {
t.plan(1);
t.ok(
typeof generator === "function",
"expect swiftObjectGenerator to be a function",
);
});
test("objectGenerator call", t => {
const tests: ITest[] = [
{
msg: "should parse 35a AST",
actual: generator({
type: "SwiftPattern",
body: [
{
type: ENodeType.line,
nodes: [
{
type: ENodeType.field,
length: { min: 0, max: 35 },
char: "a",
},
],
},
],
}),
expected: {
linesCount: 1,
lines: [
{
minChars: 0,
maxChars: 35,
regExp: "[A-Z]{0,35}",
allowedCharsClass: "[A-Z]",
},
],
minChars: 0,
maxChars: 35,
regExp: "[A-Z]{0,35}",
allowedCharsClass: "[A-Z]",
},
},
{
msg: "should parse 4a AST",
actual: generator({
type: "SwiftPattern",
body: [
{
type: ENodeType.line,
nodes: [
{
type: ENodeType.field,
length: { min: 0, max: 4 },
char: "a",
},
],
},
],
}),
expected: {
linesCount: 1,
lines: [
{
minChars: 0,
maxChars: 4,
regExp: "[A-Z]{0,4}",
allowedCharsClass: "[A-Z]",
},
],
minChars: 0,
maxChars: 4,
regExp: "[A-Z]{0,4}",
allowedCharsClass: "[A-Z]",
},
},
{
msg: "should parse 4a3c AST",
actual: generator({
type: "SwiftPattern",
body: [
{
type: ENodeType.line,
nodes: [
{
type: ENodeType.field,
length: { min: 0, max: 4 },
char: "a",
},
{
type: ENodeType.field,
length: { min: 0, max: 3 },
char: "c",
},
],
},
],
}),
expected: {
linesCount: 1,
lines: [
{
minChars: 0,
maxChars: 7,
regExp: "[A-Z]{0,4}[A-Z0-9]{0,3}",
allowedCharsClass: "[A-Z0-9]",
},
],
minChars: 0,
maxChars: 7,
regExp: "[A-Z]{0,4}[A-Z0-9]{0,3}",
allowedCharsClass: "[A-Z0-9]",
},
},
{
msg: "generate :4!c object",
actual: generator({
type: "SwiftPattern",
body: [
{
type: ENodeType.line,
nodes: [
{
type: ENodeType.sign,
char: ":",
},
{
type: ENodeType.field,
length: { min: 4, max: 4 },
char: "c",
},
],
},
],
}),
expected: {
linesCount: 1,
lines: [
{
minChars: 5,
maxChars: 5,
regExp: ":[A-Z0-9]{4,4}",
allowedCharsClass: "[:A-Z0-9]",
},
],
minChars: 5,
maxChars: 5,
regExp: ":[A-Z0-9]{4,4}",
allowedCharsClass: "[:A-Z0-9]",
},
},
{
// tslint:disable-next-line:max-line-length
msg: "generate :: object, filter out duplicates in allowedCharsClass",
actual: generator({
type: "SwiftPattern",
body: [
{
type: ENodeType.line,
nodes: [
{
type: ENodeType.sign,
char: ":",
},
{
type: ENodeType.sign,
char: ":",
},
],
},
],
}),
expected: {
linesCount: 1,
lines: [
{
minChars: 2,
maxChars: 2,
regExp: "::",
allowedCharsClass: "[:]",
},
],
minChars: 2,
maxChars: 2,
regExp: "::",
allowedCharsClass: "[:]",
},
},
{
msg: "generate multiline 3a\\n4c\\n4c object",
actual: generator({
type: "SwiftPattern",
body: [
{
type: ENodeType.line,
nodes: [
{
type: ENodeType.field,
length: { min: 0, max: 30 },
char: "a",
},
],
},
{
type: ENodeType.line,
nodes: [
{
type: ENodeType.field,
length: { min: 0, max: 4 },
char: "c",
},
],
},
{
type: ENodeType.line,
nodes: [
{
type: ENodeType.field,
length: { min: 0, max: 4 },
char: "c",
},
],
},
],
}),
expected: {
linesCount: 3,
lines: [
{
minChars: 0,
maxChars: 30,
regExp: "[A-Z]{0,30}",
allowedCharsClass: "[A-Z]",
},
{
minChars: 0,
maxChars: 4,
regExp: "[A-Z0-9]{0,4}",
allowedCharsClass: "[A-Z0-9]",
},
{
minChars: 0,
maxChars: 4,
regExp: "[A-Z0-9]{0,4}",
allowedCharsClass: "[A-Z0-9]",
},
],
minChars: 0,
maxChars: 38,
regExp: "[A-Z]{0,30}\n[A-Z0-9]{0,4}\n[A-Z0-9]{0,4}",
allowedCharsClass: "[A-Z\nA-Z0-9]",
},
},
{
msg: "generate multiline 30a\\n4c object",
actual: generator({
type: "SwiftPattern",
body: [
{
type: ENodeType.line,
nodes: [
{
type: ENodeType.field,
length: { min: 0, max: 30 },
char: "a",
},
],
},
{
type: ENodeType.line,
nodes: [
{
type: ENodeType.field,
length: { min: 0, max: 4 },
char: "c",
},
],
},
],
}),
expected: {
linesCount: 2,
lines: [
{
minChars: 0,
maxChars: 30,
regExp: "[A-Z]{0,30}",
allowedCharsClass: "[A-Z]",
},
{
minChars: 0,
maxChars: 4,
regExp: "[A-Z0-9]{0,4}",
allowedCharsClass: "[A-Z0-9]",
},
],
minChars: 0,
maxChars: 34,
regExp: "[A-Z]{0,30}\n[A-Z0-9]{0,4}",
allowedCharsClass: "[A-Z\nA-Z0-9]",
},
},
{
msg: "generate multiline 2*35a object",
actual: generator({
type: "SwiftPattern",
body: [
{
type: ENodeType.line,
optional: true,
nodes: [
{
type: ENodeType.field,
length: { min: 0, max: 35 },
char: "a",
},
],
},
{
type: ENodeType.line,
optional: true,
nodes: [
{
type: ENodeType.field,
length: { min: 0, max: 35 },
char: "a",
},
],
},
],
}),
expected: {
linesCount: 2,
lines: [
{
minChars: 0,
maxChars: 35,
regExp: "[A-Z]{0,35}",
allowedCharsClass: "[A-Z]",
},
{
minChars: 0,
maxChars: 35,
regExp: "[A-Z]{0,35}",
allowedCharsClass: "[A-Z]",
},
],
minChars: 0,
maxChars: 70,
regExp: "([A-Z]{0,35})?\n?([A-Z]{0,35})?",
allowedCharsClass: "[A-Z\n]",
},
},
{
msg: "generate [3c] object",
actual: generator({
type: "SwiftPattern",
body: [
{
type: ENodeType.line,
nodes: [
{
type: ENodeType.optional,
nodes: [
{
type: ENodeType.field,
length: { min: 0, max: 3 },
char: "c",
},
],
},
],
},
],
}),
expected: {
linesCount: 1,
lines: [
{
minChars: 0,
maxChars: 3,
regExp: "([A-Z0-9]{0,3})?",
allowedCharsClass: "[A-Z0-9]",
},
],
minChars: 0,
maxChars: 3,
regExp: "([A-Z0-9]{0,3})?",
allowedCharsClass: "[A-Z0-9]",
},
},
{
msg: "generate [3c] object",
actual: generator({
type: "SwiftPattern",
body: [
{
type: ENodeType.line,
nodes: [
{
type: ENodeType.optional,
nodes: [
{
type: ENodeType.field,
length: { min: 0, max: 3 },
char: "c",
},
],
},
],
},
],
}),
expected: {
linesCount: 1,
lines: [
{
minChars: 0,
maxChars: 3,
regExp: "([A-Z0-9]{0,3})?",
allowedCharsClass: "[A-Z0-9]",
},
],
minChars: 0,
maxChars: 3,
regExp: "([A-Z0-9]{0,3})?",
allowedCharsClass: "[A-Z0-9]",
},
},
{
msg: "generate required with trailing optional 2!a[3c] object",
actual: generator({
type: "SwiftPattern",
body: [
{
type: ENodeType.line,
nodes: [
{
type: ENodeType.field,
length: { min: 2, max: 2 },
char: "a",
},
{
type: ENodeType.optional,
nodes: [
{
type: ENodeType.field,
length: { min: 0, max: 3 },
char: "c",
},
],
},
],
},
],
}),
expected: {
linesCount: 1,
lines: [
{
minChars: 2,
maxChars: 5,
regExp: "[A-Z]{2,2}([A-Z0-9]{0,3})?",
allowedCharsClass: "[A-Z0-9]",
},
],
minChars: 2,
maxChars: 5,
regExp: "[A-Z]{2,2}([A-Z0-9]{0,3})?",
allowedCharsClass: "[A-Z0-9]",
},
},
{
msg: "generate optional with trailing required [3c]2!a object",
actual: generator({
type: "SwiftPattern",
body: [
{
type: ENodeType.line,
nodes: [
{
type: ENodeType.optional,
nodes: [
{
type: ENodeType.field,
length: { min: 0, max: 3 },
char: "c",
},
],
},
{
type: ENodeType.field,
length: { min: 2, max: 2 },
char: "a",
},
],
},
],
}),
expected: {
linesCount: 1,
lines: [
{
minChars: 2,
maxChars: 5,
regExp: "([A-Z0-9]{0,3})?[A-Z]{2,2}",
allowedCharsClass: "[A-Z0-9]",
},
],
minChars: 2,
maxChars: 5,
regExp: "([A-Z0-9]{0,3})?[A-Z]{2,2}",
allowedCharsClass: "[A-Z0-9]",
},
},
{
msg: "generate nested optional [3c[3!c]] object",
actual: generator({
type: "SwiftPattern",
body: [
{
type: ENodeType.line,
nodes: [
{
type: ENodeType.optional,
nodes: [
{
type: ENodeType.field,
length: { min: 0, max: 3 },
char: "c",
},
{
type: ENodeType.optional,
nodes: [
{
type: ENodeType.field,
length: { min: 3, max: 3 },
char: "c",
},
],
},
],
},
],
},
],
}),
expected: {
linesCount: 1,
lines: [
{
minChars: 0,
maxChars: 6,
regExp: "([A-Z0-9]{0,3}([A-Z0-9]{3,3})?)?",
allowedCharsClass: "[A-Z0-9]",
},
],
minChars: 0,
maxChars: 6,
regExp: "([A-Z0-9]{0,3}([A-Z0-9]{3,3})?)?",
allowedCharsClass: "[A-Z0-9]",
},
},
{
msg: "generate block (1a1n) object",
actual: generator({
type: "SwiftPattern",
body: [
{
type: ENodeType.line,
nodes: [
{
type: ENodeType.block,
nodes: [
{
type: ENodeType.field,
length: { min: 0, max: 1 },
char: "a",
},
{
type: ENodeType.field,
length: { min: 0, max: 1 },
char: "n",
},
],
},
],
},
],
}),
expected: {
linesCount: 1,
lines: [
{
minChars: 0,
maxChars: 2,
regExp: "([A-Z]?[0-9]?)",
allowedCharsClass: "[A-Z0-9]",
},
],
minChars: 0,
maxChars: 2,
regExp: "([A-Z]?[0-9]?)",
allowedCharsClass: "[A-Z0-9]",
},
},
{
msg: "throws when wrong AST type is supplied",
method: "throws",
actual: () => generator({
type: "Programm",
body: [],
}),
expected: /Unsupported AST type "Programm"/,
},
{
msg: "throws when unsupported char is supplied",
method: "throws",
actual: () => generator({
type: "SwiftPattern",
body: [
{
type: ENodeType.line,
nodes: [
{
type: ENodeType.field,
length: { min: 0, max: 35 },
char: "ö",
},
],
},
],
}),
expected: /Unsupported character "ö" in field/,
},
];
t.plan(tests.length);
tests.forEach(({
actual,
expected,
msg = "",
method = "deepEqual",
}) => {
t[method](actual, expected, msg);
});
});
test("getCharClass call", t => {
const tests: ITest[] = [
{
msg: "returns the char class for a",
actual: getCharClass("a"),
expected: "[A-Z]",
},
{
msg: "returns the char class for n",
actual: getCharClass("n"),
expected: "[0-9]",
},
{
msg: "returns the char class for x",
actual: getCharClass("x"),
expected: "[A-Za-z0-9\\/\\-\\?\\:\\(\\)\\.\\,\\'\\+\n ]",
},
{
msg: "returns the char class for y",
actual: getCharClass("y"),
// tslint:disable-next-line:max-line-length
expected: `[A-Z0-9\\.\\,\\-\\(\\)\\/\\=\\'\\+\\:\\?\\!\\"\\%\\&\\*\\<\\>\\; ]`,
},
{
msg: "returns the char class for z",
actual: getCharClass("z"),
// tslint:disable-next-line:max-line-length
expected: `[A-Za-z0-9\\.\\,\\-\\(\\)\\/\\=\\'\\+\\:\\?\\!\\"\\%\\&\\*\\<\\>\\;\\{\\@\\#\\_\n ]`,
},
{
msg: "returns the char class for c",
actual: getCharClass("c"),
expected: `[A-Z0-9]`,
},
{
msg: "returns the char class for h",
actual: getCharClass("h"),
expected: `[A-F0-9]`,
},
{
msg: "returns the char class for e",
actual: getCharClass("e"),
expected: `[ ]`,
},
{
msg: "returns the char class for d",
actual: getCharClass("d"),
expected: `[0-9,]`,
},
{
msg: "returns empty string for undefined char class ö",
actual: getCharClass("ö"),
expected: "",
},
];
t.plan(tests.length);
tests.forEach(({
actual,
expected,
msg = "",
method = "deepEqual",
}) => {
t[method](actual, expected, msg);
});
});
test("getQuantifier call", t => {
const tests: ITest[] = [
{
msg: "returns the quantifier for 1,2",
actual: getQuantifier(1, 2),
expected: "{1,2}",
},
{
msg: "returns the quantifier for 1,1",
actual: getQuantifier(1, 1),
expected: "",
},
{
msg: "returns the quantifier for 0,1",
actual: getQuantifier(0, 1),
expected: "?",
},
{
msg: "throws when min > max",
method: "throws",
actual: () => getQuantifier(1, 0),
expected: /Invalid quantifier, max "0" has to be equal or greater than min "1"/,
},
];
t.plan(tests.length);
tests.forEach(({
actual,
expected,
msg = "",
method = "deepEqual",
}) => {
t[method](actual, expected, msg);
});
});