pivot/test/test.js

429 lines
12 KiB
JavaScript

const assert = require('assert');
const types = require('../src/types.js');
const tokenizer = require('../src/tokenizer.js');
const parser = require('../src/parser.js');
console.log(parser.parse(tokenizer.tokenize('let x = (5 + 3);')));
describe('types.js', () => {
it('Has a Token child.', () => {
assert.equal(types.hasOwnProperty('Token'), true);
});
it('Has a Group child.', () => {
assert.equal(types.hasOwnProperty('Group'), true);
});
it('Has a Operator child.', () => {
assert.equal(types.hasOwnProperty('Operator'), true);
});
describe('Token', () => {
it('Works as a constructor', () => {
try {
let token = new types.Token('a', 'b', 'c');
} catch (err) {
throw err;
}
});
it('Has values \'type\', \'subtype\', and \'value\'', () => {
try {
let token = new types.Token('a', 'b', 'c');
if (!token.hasOwnProperty('type') || !token.hasOwnProperty('subtype') || !token.hasOwnProperty('value'))
throw new Error('Token is missing \'type\', \'subtype\', or \'value\' properties.');
if (token.type != 'a' || token.subtype != 'b' || token.value != 'c')
throw new Error('Token incorrectly set \'type\', \'subtype\', or \'value\' properties.');
} catch (err) {
throw err;
}
});
});
describe('Group', () => {
it('Works as a constructor', () => {
try {
let group = new types.Group('a', 'b');
} catch (err) {
throw err;
}
});
it('Has values \'type\', \'subtype\', and \'tokens\'', () => {
try {
let group = new types.Group('a', 'b');
if (!group.hasOwnProperty('type') || !group.hasOwnProperty('subtype') || !group.hasOwnProperty('tokens'))
throw new Error('Group is missing \'type\', \'subtype\', or \'tokens\' properties.');
if (group.type != 'group' || group.subtype != 'a' || group.tokens != 'b')
throw new Error('Group incorrectly set \'type\', \'subtype\', or \'tokens\' properties.');
} catch (err) {
throw err;
}
});
});
// describe('Operator', () => {
// it('Works as a constructor', () => {
// try {
// let op = new types.Operator('dual', '+', ['3','4']);
// } catch (err) {
// throw err;
// }
// });
// it('Has values \'type\', \'subtype\', \'value\', and \'operands\'', () => {
// try {
// let op = new types.Operator('dual', '+', ['3','4']);
// if (!op.hasOwnProperty('type') || !op.hasOwnProperty('subtype') || !op.hasOwnProperty('value') || !op.hasOwnProperty('operands'))
// throw new Error('Operator is missing \'type\', \'subtype\', \'value\', or \'operands\' properties.');
// if (op.type != 'operator' || op.subtype != 'dual' || op.value != '+' || op.operands[0] != '3')
// throw new Error('Operator incorrectly set \'type\', \'subtype\', \'value\', or \'operands\' properties.');
// } catch (err) {
// throw err;
// }
// });
// });
});
describe('tokenizer.js', () => {
it('combineEscapedChars works', () => {
assert.equal(tokenizer.util.combineEscapedChars(`let x = 'test\\nnewline';`.split('')).join(''), `let x = 'test\\nnewline';`);
});
it('removeComments works', () => {
assert.equal(tokenizer.util.removeComments(`// Comment\nlet i = 0;`.split('')).join(''), `let i = 0;`);
});
it('changeKeywords works', () => {
let tokens = tokenizer.util.changeKeywords([{
type: 'name',
subtype: 'variable',
value: 'let'
}, {
type: 'name',
subtype: 'variable',
value: 'x'
}]);
let correct = [{
type: 'name',
subtype: 'keyword',
value: 'let'
}, {
type: 'name',
subtype: 'variable',
value: 'x'
}];
let isCorrect = true;
tokens.forEach((t, i) => {
if (t.type != correct[i].type)
throw new Error('Changed type: Expected \'' + correct[i].type + '\' but got \'' + t.type + '\'')
else if (t.subtype != correct[i].subtype)
throw new Error('Incorrectly changed subtype: Expected \'' + correct[i].subtype + '\' but got \'' + t.subtype + '\'')
else if (t.value != correct[i].value)
throw new Error('Changed value: Expected \'' + correct[i].value + '\' but got \'' + t.value + '\'')
});
});
it('getDelimiterToken works', () => {
let token = tokenizer.util.getDelimiterToken(')');
if (token.type != 'delimiter')
throw new Error('Incorrect type: Expected \'delimiter\' but got \'' + token.type + '\'')
else if (token.subtype != 'right')
throw new Error('Incorrect subtype: Expected \'right\' but got \'' + token.subtype + '\'')
else if (token.value != 'parenthesis')
throw new Error('Incorrect value: Expected \'parenthesis\' but got \'' + token.value + '\'')
});
it('operatorType works', () => {
assert.equal(tokenizer.util.operatorType('++'), 'postfix');
assert.equal(tokenizer.util.operatorType(';'), 'none');
assert.equal(tokenizer.util.operatorType('+'), 'dual');
});
it('determineCharType works', () => {
assert.equal(tokenizer.util.determineCharType('+'), 'operator');
assert.equal(tokenizer.util.determineCharType('"'), 'string delimiter');
assert.equal(tokenizer.util.determineCharType('4'), 'digit');
});
it('determineType works', () => {
assert.equal(tokenizer.util.determineType('let'), 'keyword');
assert.equal(tokenizer.util.determineType('dog'), 'unknown');
});
});
describe('parser.js', () => {
it('addIndexes works', () => {
let tokens = parser.util.addIndexes([{
type: 'name',
subtype: 'keyword',
value: 'let'
}, {
type: 'name',
subtype: 'variable',
value: 'x'
}]);
let correct = [{
type: 'name',
subtype: 'keyword',
value: 'let',
index: 0
}, {
type: 'name',
subtype: 'variable',
value: 'x',
index: 1
}];
let isCorrect = true;
tokens.forEach((t, i) => {
if (t.type != correct[i].type)
throw new Error('Changed type: Expected \'' + correct[i].type + '\' but got ' + t.type)
else if (t.subtype != correct[i].subtype)
throw new Error('Changed subtype: Expected \'' + correct[i].subtype + '\' but got ' + t.subtype)
else if (t.value != correct[i].value)
throw new Error('Changed value: Expected \'' + correct[i].value + '\' but got ' + t.value)
else if (t.index != correct[i].index)
throw new Error('Incorrect index: Expected \'' + correct[i].index + '\' but got ' + t.index)
});
});
it('addLevels works', () => {
let tokens = parser.util.addLevels([{
type: 'name',
subtype: 'keyword',
value: 'let',
index: 0
}, {
type: 'name',
subtype: 'variable',
value: 'x',
index: 1
}, {
type: 'operator',
subtype: 'dual',
value: '=',
index: 2
}, {
type: 'delimiter',
subtype: 'left',
value: 'parenthesis',
index: 3
}, {
type: 'number',
subtype: 'n/a',
value: '5',
index: 4
}, {
type: 'delimiter',
subtype: 'right',
value: 'parenthesis',
index: 5
}]);
let correct = [{
type: 'name',
subtype: 'keyword',
value: 'let',
index: 0,
level: 0
}, {
type: 'name',
subtype: 'variable',
value: 'x',
index: 1,
level: 0
}, {
type: 'operator',
subtype: 'dual',
value: '=',
index: 2,
level: 0
}, {
type: 'delimiter',
subtype: 'left',
value: 'parenthesis',
index: 3,
level: 1
}, {
type: 'number',
subtype: 'n/a',
value: '5',
index: 4,
level: 1
}, {
type: 'delimiter',
subtype: 'right',
value: 'parenthesis',
index: 5,
level: 1
}];
let isCorrect = true;
tokens.forEach((t, i) => {
if (t.type != correct[i].type)
throw new Error('Changed type: Expected \'' + correct[i].type + '\' but got ' + t.type)
else if (t.subtype != correct[i].subtype)
throw new Error('Changed subtype: Expected \'' + correct[i].subtype + '\' but got \'' + t.subtype + '\'')
else if (t.value != correct[i].value)
throw new Error('Changed value: Expected \'' + correct[i].value + '\' but got \'' + t.value + '\'')
else if (t.index != correct[i].index)
throw new Error('Incorrect index: Expected \'' + correct[i].index + '\' but got \'' + t.index + '\'')
else if (t.level != correct[i].level)
throw new Error('Incorrect level: Expected \'' + correct[i].level + '\' but got \'' + t.level + '\'')
});
});
it('getDeepestLevel works', () => {
let deepestLevel = parser.util.getDeepestLevel([{
type: 'name',
subtype: 'keyword',
value: 'let',
index: 0,
level: 0
}, {
type: 'name',
subtype: 'variable',
value: 'x',
index: 1,
level: 0
}, {
type: 'operator',
subtype: 'dual',
value: '=',
index: 2,
level: 0
}, {
type: 'delimiter',
subtype: 'left',
value: 'parenthesis',
index: 3,
level: 1
}, {
type: 'number',
subtype: 'n/a',
value: '5',
index: 4,
level: 1
}, {
type: 'operator',
subtype: 'dual',
value: '+',
index: 5,
level: 1
}, {
type: 'delimiter',
subtype: 'left',
value: 'parenthesis',
index: 6,
level: 2
}, {
type: 'number',
subtype: 'n/a',
value: '6',
index: 7,
level: 2
}, {
type: 'operator',
subtype: 'dual',
value: '*',
index: 8,
level: 2
}, {
type: 'number',
subtype: 'n/a',
value: '2',
index: 9,
level: 2
}, {
type: 'delimiter',
subtype: 'right',
value: 'parenthesis',
index: 10,
level: 2
}, {
type: 'delimiter',
subtype: 'right',
value: 'parenthesis',
index: 11,
level: 1
}, {
type: 'operator',
subtype: 'none',
value: ';',
index: 12,
level: 0
}]);
if (deepestLevel != 2)
throw new Error('Incorrect deepestLevel. Expected \'2\' but got \'' + deepestLevel + '\'');
});
it('combineGroups works', () => {
let ast = parser.util.combineGroups([{
type: 'name',
subtype: 'keyword',
value: 'let',
index: 0,
level: 0
}, {
type: 'name',
subtype: 'variable',
value: 'x',
index: 1,
level: 0
}, {
type: 'operator',
subtype: 'dual',
value: '=',
index: 2,
level: 0
}, {
type: 'delimiter',
subtype: 'left',
value: 'parenthesis',
index: 3,
level: 1
}, {
type: 'number',
subtype: 'n/a',
value: '5',
index: 4,
level: 1
}, {
type: 'operator',
subtype: 'dual',
value: '+',
index: 5,
level: 1
}, {
type: 'delimiter',
subtype: 'left',
value: 'parenthesis',
index: 6,
level: 2
}, {
type: 'number',
subtype: 'n/a',
value: '6',
index: 7,
level: 2
}, {
type: 'operator',
subtype: 'dual',
value: '*',
index: 8,
level: 2
}, {
type: 'number',
subtype: 'n/a',
value: '2',
index: 9,
level: 2
}, {
type: 'delimiter',
subtype: 'right',
value: 'parenthesis',
index: 10,
level: 2
}, {
type: 'delimiter',
subtype: 'right',
value: 'parenthesis',
index: 11,
level: 1
}, {
type: 'operator',
subtype: 'none',
value: ';',
index: 12,
level: 0
}]);
if (ast[3].type != 'group')
throw new Error('Incorrectly combined group.');
if (ast[3].tokens[3].type != 'group')
throw new Error('Incorrectly combined group.');
});
});