brogue
Version:
A Grammar based generative text library based on Tracery.
167 lines (138 loc) • 8.31 kB
text/typescript
/* eslint-disable babel/no-unused-expressions */
import { expect } from 'chai';
import 'mocha';
import { Lexeme } from '../src/brogue/grammar';
import { parseLexeme } from '../src/brogue/parse';
describe('parseLexeme', () => {
it('parses empty lexeme', () => {
const lexeme = parseLexeme("");
expect(lexeme.originalString).to.equal('');
expect(lexeme.formatString).to.equal('');
expect(lexeme.expansions).to.have.lengthOf(0);
});
describe('parsing expansions', () => {
it('fails to parse invalid expansions', () => {
expect(() => { parseLexeme("{"); }).to.throw();
expect(() => { parseLexeme("}"); }).to.throw();
expect(() => { parseLexeme("}cat.a"); }).to.throw();
expect(() => { parseLexeme("{cat.a"); }).to.throw();
expect(() => { parseLexeme("{cat.a{}"); }).to.throw();
expect(() => { parseLexeme("{cat.a}}"); }).to.throw();
expect(() => { parseLexeme("{{cat.a}"); }).to.throw();
expect(() => { parseLexeme("{{cat.a} {dog}}"); }).to.throw();
});
it('parses lexeme with standard expansions', () => {
const str = '{cat} {dog}';
const lexeme = parseLexeme(str);
expect(lexeme.expansions).to.have.lengthOf(2);
const expansionNames = lexeme.expansions.map((x) => x.name);
expect(expansionNames).to.include.members(['cat', 'dog']);
expect(lexeme.expansions.every((l) => !l.isDecorator)).to.be.true;
expect(lexeme.originalString).to.equal(str);
expect(lexeme.formatString).to.equal('{0} {1}');
});
it('parses lexeme with decorator expansions', () => {
const str = '{{cat}} {{dog}}';
const lexeme = parseLexeme(str);
expect(lexeme.expansions).to.have.lengthOf(2);
const expansionNames = lexeme.expansions.map((x) => x.name);
expect(expansionNames).to.include.members(['cat', 'dog']);
expect(lexeme.expansions.every((l) => l.isDecorator)).to.be.true;
expect(lexeme.originalString).to.equal(str);
expect(lexeme.formatString).to.equal('{0} {1}');
});
describe('parsing modifiers', () => {
it('fails to parse invalid modifiers', () => {
expect(() => { parseLexeme("{cat..}"); }).to.throw();
expect(() => { parseLexeme("{cat. .}"); }).to.throw();
expect(() => { parseLexeme("{cat.(}"); }).to.throw();
expect(() => { parseLexeme("{cat.)}"); }).to.throw();
expect(() => { parseLexeme("{cat.())}"); }).to.throw();
});
it('parses modifiers without argument lists', () => {
const lexeme = parseLexeme("{cat.a} {cat.a()}");
expect(lexeme.expansions[0].modifierCalls).to.have.lengthOf(1);
expect(lexeme.expansions[0].modifierCalls[0].name).to.equal('a');
expect(lexeme.expansions[0].modifierCalls[0].args).to.have.lengthOf(0);
expect(lexeme.expansions[1].modifierCalls).to.have.lengthOf(1);
expect(lexeme.expansions[1].modifierCalls[0].name).to.equal('a');
expect(lexeme.expansions[1].modifierCalls[0].args).to.have.lengthOf(0);
expect(lexeme.formatString).to.equal('{0} {1}');
});
it('parses chained modifiers', () => {
const lexeme = parseLexeme("{cat.a.b().c}");
expect(lexeme.expansions[0].modifierCalls).to.have.lengthOf(3);
expect(lexeme.expansions[0].modifierCalls[0].name).to.equal('a');
expect(lexeme.expansions[0].modifierCalls[1].name).to.equal('b');
expect(lexeme.expansions[0].modifierCalls[2].name).to.equal('c');
});
it('parses modifiers with arguments', () => {
function expectArguments(lexeme: Lexeme, ...args: any[]): void {
expect(lexeme.expansions[0].modifierCalls).to.have.lengthOf(1);
expect(lexeme.expansions[0].modifierCalls[0].name).to.equal('a');
expect(lexeme.expansions[0].modifierCalls[0].args).to.have.lengthOf(args.length);
for (let i = 0; i < args.length; ++i) {
expect(lexeme.expansions[0].modifierCalls[0].args[i]).to.equal(args[i]);
}
}
expectArguments(parseLexeme("{cat.a('string')}"), 'string');
expectArguments(parseLexeme('{cat.a("string")}'), 'string');
expectArguments(parseLexeme('{cat.a("\\"string\\"")}'), '"string"');
expectArguments(parseLexeme('{cat.a(", )")}'), ', )');
expectArguments(parseLexeme('{cat.a(1)}'), 1);
expectArguments(parseLexeme('{cat.a(2.5)}'), 2.5);
expectArguments(parseLexeme('{cat.a("string", 1, 30)}'), 'string', 1, 30);
expectArguments(parseLexeme('{cat.a("string {thing}")}'), 'string {thing}');
});
it('parses chained modifiers with arguments', () => {
function expectModifier(lexeme: Lexeme, i: number, funcName: string, ...args: any[]): void {
expect(lexeme.expansions[0].modifierCalls[i].name).to.equal(funcName);
expect(lexeme.expansions[0].modifierCalls[i].args).to.have.lengthOf(args.length);
for (let j = 0; j < args.length; ++j) {
expect(lexeme.expansions[0].modifierCalls[i].args[j]).to.equal(args[j]);
}
}
const lexeme = parseLexeme('{cat.a(1,2).b("string")}');
expectModifier(lexeme, 0, 'a', 1, 2);
expectModifier(lexeme, 1, 'b', 'string');
});
});
describe('parsing inline variables', () => {
function expectVariables(lexeme: Lexeme, variables: any): void {
expect(lexeme.variables).to.not.be.undefined;
if (!lexeme.variables) {
return;
}
expect(lexeme.variables).to.be.lengthOf(Object.keys(variables).length);
for (const key of Object.keys(variables)) {
const value: any = variables[key];
expect(lexeme.variables).has.key(key);
expect(lexeme.variables.get(key)!.lexeme.originalString).to.equal(value.originalString);
expect(lexeme.variables.get(key)!.lexeme.formatString).to.equal(value.formatString);
}
}
it('fails to parse invalid variables', () => {
expect(() => { parseLexeme('{='); }).to.throw();
expect(() => { parseLexeme('{= '); }).to.throw();
expect(() => { parseLexeme('{=}'); }).to.throw();
expect(() => { parseLexeme('{= }'); }).to.throw();
expect(() => { parseLexeme('{ =}'); }).to.throw();
expect(() => { parseLexeme('{ = }'); }).to.throw();
expect(() => { parseLexeme('{a=b}'); }).to.throw();
});
it('parses inline variables', () => {
expectVariables(parseLexeme('{var= {cat}}'), { var: { originalString: '{cat}', formatString: '{0}' } });
expectVariables(parseLexeme('{var= {cat.a}}'), { var: { originalString: '{cat.a}', formatString: '{0}' } });
expectVariables(parseLexeme('{var= {cat}{dog}}'), { var: { originalString: '{cat}{dog}', formatString: '{0}{1}' } });
expectVariables(parseLexeme('{var= {cat} dog}'), { var: { originalString: '{cat} dog', formatString: '{0} dog' } });
expectVariables(parseLexeme('{var= cat=dog}'), { var: { originalString: 'cat=dog', formatString: 'cat=dog' } });
});
it('strips inline variables from lexeme format string', () => {
let lexeme = parseLexeme('{var= {cat}}');
expect(lexeme.formatString).to.equal('');
lexeme = parseLexeme('{var= {cat}} {cat}');
expect(lexeme.formatString).to.equal(' {0}');
});
});
});
});