brogue
Version:
A Grammar based generative text library based on Tracery.
283 lines (215 loc) • 10.4 kB
text/typescript
import { expect } from 'chai';
import sinon from 'sinon';
import 'mocha';
import { expand } from '../src/brogue/expand';
import { parseGrammarObject } from '../src/brogue/parse';
describe('expand', () => {
let grammarObject: any;
beforeEach(() => {
grammarObject = {
ruleA: ['a', 'b'],
ruleB: ['c', 'd'],
};
});
it('should expand empty string', () => {
const grammar = parseGrammarObject(grammarObject);
expect(expand(grammar, '')).to.equal('');
});
it('should expand expansion', () => {
const grammar = parseGrammarObject(grammarObject);
sinon.stub(grammar.random, 'random').returns(0);
expect(expand(grammar, '{ruleA}')).to.equal('a');
});
it('should expand multiple expansions', () => {
const grammar = parseGrammarObject(grammarObject);
sinon.stub(grammar.random, 'random').returns(0);
expect(expand(grammar, '{ruleA} {ruleB}')).to.equal('a c');
});
describe('modifiers', () => {
it('fails to invoke unrecognized modifiers', () => {
const grammar = parseGrammarObject(grammarObject);
expect(() => expand(grammar, '{ruleA.unrecognizedModifier}')).to.throw();
expect(() => expand(grammar, '{ruleA.unrecognizedModifier()}')).to.throw();
});
it('invokes custom modifiers', () => {
const grammar = parseGrammarObject(grammarObject);
grammar.modifiers.set('test', (s: string) => `${s}_test`);
sinon.stub(grammar.random, 'random').returns(0);
expect(expand(grammar, '{ruleA.test}')).to.equal('a_test');
});
describe('built-in modifiers', () => {
it('"capitalize" modifier', () => {
const grammar = parseGrammarObject({ sentence: 'a cat and dog' });
expect(expand(grammar, '{sentence.capitalize}')).to.equal('A cat and dog');
});
it('"capitalizeall" modifier', () => {
const grammar = parseGrammarObject({ sentence: 'a cat and dog' });
expect(expand(grammar, '{sentence.capitalizeall}')).to.equal('A Cat And Dog');
});
it('"quotes" modifier', () => {
const grammar = parseGrammarObject({ sentence: 'a cat and dog' });
expect(expand(grammar, '{sentence.quotes}')).to.equal('"a cat and dog"');
});
it('"times" modifier', () => {
const grammar = parseGrammarObject({ letter: 'a' });
expect(expand(grammar, '{letter.times(3)}')).to.equal('a a a');
expect(() => expand(grammar, '{letter.times}')).to.throw();
expect(() => expand(grammar, '{letter.times("cat")}')).to.throw();
});
it('"a" modifier', () => {
const grammar = parseGrammarObject({ noun: 'cat' });
expect(expand(grammar, '{noun.a}')).to.equal('a cat');
});
it('"s" modifier', () => {
const grammar = parseGrammarObject({ noun: 'cat' });
expect(expand(grammar, '{noun.s}')).to.equal('cats');
});
it('"singular" modifier', () => {
const grammar = parseGrammarObject({ nounPlural: 'cats' });
expect(expand(grammar, '{nounPlural.singular}')).to.equal('cat');
});
it('"past" modifier', () => {
const grammar = parseGrammarObject({ verb: 'run' });
expect(expand(grammar, '{verb.past}')).to.equal('ran');
});
it('"present" modifier', () => {
const grammar = parseGrammarObject({ verb: 'run' });
expect(expand(grammar, '{verb.present}')).to.equal('runs');
});
it('"future" modifier', () => {
const grammar = parseGrammarObject({ verb: 'run' });
expect(expand(grammar, '{verb.future}')).to.equal('will run');
});
it('"ing" modifier', () => {
const grammar = parseGrammarObject({ verb: 'run' });
expect(expand(grammar, '{verb.ing}')).to.equal('running');
});
it('"infinitive" modifier', () => {
const grammar = parseGrammarObject({ verb: 'runs' });
expect(expand(grammar, '{verb.infinitive}')).to.equal('run');
});
it('"nounify" modifier', () => {
const grammar = parseGrammarObject({
verbA: 'run',
verbB: 'paint',
verbC: 'debate',
});
expect(expand(grammar, '{verbA.nounify}')).to.equal('runner');
expect(expand(grammar, '{verbB.nounify}')).to.equal('painter');
expect(expand(grammar, '{verbC.nounify}')).to.equal('debater');
});
it('"possessive" modifier', () => {
const grammar = parseGrammarObject({ noun: 'cat' });
expect(expand(grammar, '{noun.possessive}')).to.equal('cat\'s');
});
it('"positive" modifier', () => {
const grammar = parseGrammarObject({
verbNegative: 'does not run',
});
expect(expand(grammar, '{verbNegative.positive}')).to.equal('does run');
});
it('"negative" modifier', () => {
const grammar = parseGrammarObject({ verb: 'run' });
expect(expand(grammar, '{verb.negative}')).to.equal('does not run');
});
it('"numberToWords" modifier', () => {
const grammar = parseGrammarObject({ number: '3' });
expect(expand(grammar, '{number.numberToWords}')).to.equal('three');
});
it('"randomNumber" modifier', () => {
const grammar = parseGrammarObject({});
sinon.stub(grammar.random, 'intBetween').returns(3);
expect(expand(grammar, '{.randomNumber(1,5)}')).to.equal('3');
});
it('"roll" modifier', () => {
const grammar = parseGrammarObject({});
let randStub = sinon.stub(grammar.random, 'intBetween');
randStub.onCall(0).returns(1);
randStub.onCall(1).returns(2);
expect(expand(grammar, '{.roll("2d4+1")}')).to.equal('4');
(grammar.random.intBetween as any).restore();
randStub = sinon.stub(grammar.random, 'intBetween');
randStub.onCall(0).returns(1);
randStub.onCall(1).returns(2);
expect(expand(grammar, '{.roll("2d4-1")}')).to.equal('2');
});
it('"uniques" modifier', () => {
const grammar = parseGrammarObject({
testSimple: [
{ a: 9999 },
{ b: 0.0001 },
{ c: 0.0001 },
],
testNonFinalized1: [
{ "{rule1}": 9999 },
{ z: 0.0001 },
],
testNonFinalized2: [
{ "{rule1} {rule2}": 9999 },
{ z: 0.0001 },
],
testFinalized: [
{ "{{rule1}}": 9999 },
{ z: 0.0001 },
],
rule1: [
'a', 'b',
],
rule2: [
'c', 'd',
],
});
sinon.stub(grammar.random, 'random').returns(0);
expect(expand(grammar, '{.uniques("testSimple", 3, ", ")}')).to.equal('a, b, c');
expect(expand(grammar, '{.uniques("testNonFinalized1", 3, ", ")}')).to.equal('a, b, z');
expect(expand(grammar, '{.uniques("testNonFinalized2", 3, ", ")}')).to.equal('a c, b d, z');
expect(expand(grammar, '{.uniques("testFinalized", 3, ", ")}')).to.equal('a, z');
});
it('"choose" modifier', () => {
const grammar = parseGrammarObject({ rule: 'minnow' });
sinon.stub(grammar.random, 'range').returns(0);
expect(expand(grammar, '{.choose("cat", "dog", "bird")}')).to.equal('cat');
expect(expand(grammar, '{.choose(1, 2, 3)}')).to.equal('1');
expect(expand(grammar, '{.choose("{rule}")}')).to.equal('minnow');
});
});
});
describe('variables', () => {
it('expands global variables', () => {
grammarObject._variables = [
'{$ruleA= {ruleA}}',
];
const grammar = parseGrammarObject(grammarObject);
sinon.stub(grammar.random, 'random')
.onCall(0).returns(0)
.returns(0.999);
expect(expand(grammar, '{$ruleA} {$ruleA} {ruleA}')).to.equal('a a b');
});
it('expands scoped variables in same scope', () => {
const grammar = parseGrammarObject(grammarObject);
sinon.stub(grammar.random, 'random')
.onCall(0).returns(0)
.returns(0.999);
expect(expand(grammar, '{$ruleA= {ruleA}}{$ruleA} {$ruleA} {ruleA}')).to.equal('a a b');
(grammar.random.random as any).restore();
sinon.stub(grammar.random, 'random')
.onCall(0).returns(0)
.returns(0.999);
expect(expand(grammar, '{$ruleA} {$ruleA} {ruleA}{$ruleA= {ruleA}}')).to.equal('a a b');
});
it('fails to expand scoped variables in parent scope', () => {
const grammar = parseGrammarObject({
outer: '{inner} {var}',
inner: '{var= cat}',
});
expect(() => expand(grammar, '{outer}')).to.throw();
});
it('expands scoped variables in child scope', () => {
const grammar = parseGrammarObject({
outer: '{var= cat}{inner}',
inner: '{var}',
});
expect(expand(grammar, '{outer}')).to.equal('cat');
});
});
});