elliptical
Version:
Interactive natural-language interfaces
1,116 lines (1,053 loc) • 25.5 kB
JSX
/** @jsx createElement */
/* eslint-env mocha */
import createElement from '../src/element'
import {compileAndTraverse} from './_util'
import { expect } from 'chai'
describe('sequence', () => {
it('puts two elements in order', () => {
const grammar = (
<sequence>
<literal text='super' />
<literal text='man' />
</sequence>
)
const options = compileAndTraverse(grammar, '')
expect(options).to.eql([{
text: null,
words: [{text: 'super', input: false}, {text: 'man', input: false}],
result: {},
score: 1,
qualifiers: [],
categories: [],
arguments: [],
annotations:[],
data: []
}])
})
it('handles an optional child', () => {
const grammar = (
<sequence>
<literal text='super' />
<literal text=' ' optional />
<literal text='man' />
</sequence>
)
const options = compileAndTraverse(grammar, '')
expect(options).to.eql([{
text: null,
words: [
{text: 'super', input: false},
{text: 'man', input: false}
],
result: {},
score: 1,
categories: [],
arguments: [],
qualifiers: [],
annotations:[],
data: []
}, {
text: null,
words: [
{text: 'super', input: false},
{text: ' ', input: false},
{text: 'man', input: false}
],
result: {},
score: 1,
categories: [],
arguments: [],
qualifiers: [],
annotations:[],
data: []
}])
})
it('handles an ellipsis', () => {
const grammar = (
<sequence>
<literal text='super' ellipsis />
<literal text='man' />
</sequence>
)
let options
options = compileAndTraverse(grammar, '')
expect(options).to.eql([{
text: null,
words: [{text: 'super', input: false}],
result: {},
score: 1,
categories: [],
arguments: [],
qualifiers: [],
annotations:[],
data: []
}])
options = compileAndTraverse(grammar, 'super')
expect(options).to.eql([{
text: '',
words: [{text: 'super', input: true}],
result: {},
score: 1,
qualifiers: [],
categories: [],
arguments: [],
annotations:[],
data: []
}, {
text: null,
words: [{text: 'super', input: true}, {text: 'man', input: false}],
result: {},
score: 1,
qualifiers: [],
categories: [],
arguments: [],
annotations:[],
data: []
}])
options = compileAndTraverse(grammar, 'superm')
expect(options).to.eql([{
text: null,
words: [
{text: 'super', input: true},
{text: 'm', input: true},
{text: 'an', input: false}
],
result: {},
score: 1,
qualifiers: [],
categories: [],
arguments: [],
annotations:[],
data: []
}])
})
it('does not output an ellipsis for the last child', () => {
const grammar = (
<sequence>
<literal text='super' />
<literal text='man' ellipsis />
<literal text='rocks' ellipsis />
</sequence>
)
let options
options = compileAndTraverse(grammar, '')
expect(options).to.eql([{
text: null,
words: [{text: 'super', input: false}, {text: 'man', input: false}],
result: {},
score: 1,
qualifiers: [],
categories: [],
arguments: [],
annotations:[],
data: []
}])
options = compileAndTraverse(grammar, 'super')
expect(options).to.eql([{
text: null,
words: [{text: 'super', input: true}, {text: 'man', input: false}],
result: {},
score: 1,
qualifiers: [],
categories: [],
arguments: [],
annotations:[],
data: []
}])
options = compileAndTraverse(grammar, 'superman')
expect(options).to.eql([{
text: '',
words: [
{text: 'super', input: true},
{text: 'man', input: true}
],
result: {},
score: 1,
qualifiers: [],
categories: [],
arguments: [],
annotations:[],
data: []
}, {
text: null,
words: [
{text: 'super', input: true},
{text: 'man', input: true},
{text: 'rocks', input: false}
],
result: {},
score: 1,
qualifiers: [],
categories: [],
arguments: [],
annotations:[],
data: []
}])
options = compileAndTraverse(grammar, 'supermanr')
expect(options).to.eql([{
text: null,
words: [
{text: 'super', input: true},
{text: 'man', input: true},
{text: 'r', input: true},
{text: 'ocks', input: false}
],
result: {},
score: 1,
qualifiers: [],
categories: [],
arguments: [],
annotations:[],
data: []
}])
})
it('handles an ellipsis that is optional', () => {
const grammar = (
<sequence>
<literal text='the' />
<literal text='super' ellipsis optional />
<literal text='man' />
</sequence>
)
let options
options = compileAndTraverse(grammar, '')
expect(options).to.eql([{
text: null,
words: [{text: 'the', input: false}],
result: {},
score: 1,
qualifiers: [],
categories: [],
arguments: [],
annotations:[],
data: []
}, {
text: null,
words: [{text: 'the', input: false}, {text: 'super', input: false}],
result: {},
score: 1,
qualifiers: [],
categories: [],
arguments: [],
annotations:[],
data: []
}])
options = compileAndTraverse(grammar, 'the')
expect(options).to.eql([{
text: '',
words: [{text: 'the', input: true}],
result: {},
score: 1,
qualifiers: [],
categories: [],
arguments: [],
annotations:[],
data: []
}, {
text: null,
words: [{text: 'the', input: true}, {text: 'man', input: false}],
result: {},
score: 1,
qualifiers: [],
categories: [],
arguments: [],
annotations:[],
data: []
}, {
text: null,
words: [{text: 'the', input: true}, {text: 'super', input: false}],
result: {},
score: 1,
qualifiers: [],
categories: [],
arguments: [],
annotations:[],
data: []
}])
options = compileAndTraverse(grammar, 'thesuper')
expect(options).to.eql([{
text: '',
words: [{text: 'the', input: true}, {text: 'super', input: true}],
result: {},
score: 1,
categories: [],
arguments: [],
qualifiers: [],
annotations:[],
data: []
}, {
text: null,
words: [
{text: 'the', input: true},
{text: 'super', input: true},
{text: 'man', input: false}
],
result: {},
score: 1,
categories: [],
arguments: [],
qualifiers: [],
annotations:[],
data: []
}])
options = compileAndTraverse(grammar, 'thesuperm')
expect(options).to.eql([{
text: null,
words: [
{text: 'the', input: true},
{text: 'super', input: true},
{text: 'm', input: true},
{text: 'an', input: false}
],
result: {},
score: 1,
categories: [],
arguments: [],
qualifiers: [],
annotations:[],
data: []
}])
})
it('does not double output if an optional follows an ellipsis', () => {
const grammar = (
<sequence>
<literal text='the' />
<literal text='super' ellipsis optional />
<literal text='man' optional />
<literal text='rocks' />
</sequence>
)
let options
options = compileAndTraverse(grammar, '')
expect(options).to.eql([{
text: null,
words: [{text: 'the', input: false}],
result: {},
score: 1,
qualifiers: [],
categories: [],
arguments: [],
annotations:[],
data: []
}, {
text: null,
words: [{text: 'the', input: false}, {text: 'super', input: false}],
result: {},
score: 1,
qualifiers: [],
categories: [],
arguments: [],
annotations:[],
data: []
}])
options = compileAndTraverse(grammar, 'the')
expect(options).to.eql([{
text: '',
words: [{text: 'the', input: true}],
result: {},
score: 1,
qualifiers: [],
categories: [],
arguments: [],
annotations:[],
data: []
}, {
text: null,
words: [{text: 'the', input: true}, {text: 'rocks', input: false}],
result: {},
score: 1,
qualifiers: [],
categories: [],
arguments: [],
annotations:[],
data: []
}, {
text: null,
words: [
{text: 'the', input: true},
{text: 'man', input: false},
{text: 'rocks', input: false}
],
result: {},
score: 1,
qualifiers: [],
categories: [],
arguments: [],
annotations:[],
data: []
}, {
text: null,
words: [{text: 'the', input: true}, {text: 'super', input: false}],
result: {},
score: 1,
qualifiers: [],
categories: [],
arguments: [],
annotations:[],
data: []
}])
options = compileAndTraverse(grammar, 'thesuper')
expect(options).to.eql([{
text: '',
words: [{text: 'the', input: true}, {text: 'super', input: true}],
result: {},
score: 1,
qualifiers: [],
categories: [],
arguments: [],
annotations:[],
data: []
}, {
text: null,
words: [
{text: 'the', input: true},
{text: 'super', input: true},
{text: 'rocks', input: false}
],
result: {},
score: 1,
categories: [],
arguments: [],
qualifiers: [],
annotations:[],
data: []
}, {
text: null,
words: [
{text: 'the', input: true},
{text: 'super', input: true},
{text: 'man', input: false},
{text: 'rocks', input: false}
],
result: {},
score: 1,
qualifiers: [],
categories: [],
arguments: [],
annotations:[],
data: []
}])
options = compileAndTraverse(grammar, 'thesuperm')
expect(options).to.eql([{
text: null,
words: [
{text: 'the', input: true},
{text: 'super', input: true},
{text: 'm', input: true},
{text: 'an', input: false},
{text: 'rocks', input: false}
],
result: {},
score: 1,
categories: [],
arguments: [],
qualifiers: [],
annotations:[],
data: []
}])
})
it('does not double output if an optional ellipsis follows an ellipsis', () => {
const grammar = (
<sequence>
<literal text='the' />
<literal text='super' ellipsis optional />
<literal text='man' ellipsis optional />
<literal text='rocks' />
</sequence>
)
let options
/*
the opt1 opt2 ell2
the rocks opt1 opt2
the man opt1
the super
*/
options = compileAndTraverse(grammar, '')
expect(options).to.eql([{
text: null,
words: [{text: 'the', input: false}],
result: {},
score: 1,
categories: [],
arguments: [],
qualifiers: [],
annotations:[],
data: []
}, {
text: null,
words: [{text: 'the', input: false}, {text: 'super', input: false}],
result: {},
score: 1,
qualifiers: [],
categories: [],
arguments: [],
annotations:[],
data: []
}])
options = compileAndTraverse(grammar, 'the')
expect(options).to.eql([{
text: '',
words: [{text: 'the', input: true}],
result: {},
score: 1,
qualifiers: [],
categories: [],
arguments: [],
annotations:[],
data: []
}, {
text: null,
words: [{text: 'the', input: true}, {text: 'rocks', input: false}],
result: {},
score: 1,
categories: [],
arguments: [],
qualifiers: [],
annotations:[],
data: []
}, {
text: null,
words: [{text: 'the', input: true}, {text: 'man', input: false}],
result: {},
score: 1,
qualifiers: [],
categories: [],
arguments: [],
annotations:[],
data: []
}, {
text: null,
words: [{text: 'the', input: true}, {text: 'super', input: false}],
result: {},
score: 1,
qualifiers: [],
categories: [],
arguments: [],
annotations:[],
data: []
}])
options = compileAndTraverse(grammar, 'thesuper')
expect(options).to.eql([{
text: '',
words: [{text: 'the', input: true}, {text: 'super', input: true}],
result: {},
score: 1,
qualifiers: [],
categories: [],
arguments: [],
annotations:[],
data: []
}, {
text: null,
words: [
{text: 'the', input: true},
{text: 'super', input: true},
{text: 'rocks', input: false}
],
result: {},
score: 1,
qualifiers: [],
categories: [],
arguments: [],
annotations:[],
data: []
}, {
text: null,
words: [
{text: 'the', input: true},
{text: 'super', input: true},
{text: 'man', input: false}
],
result: {},
score: 1,
qualifiers: [],
categories: [],
arguments: [],
annotations:[],
data: []
}])
options = compileAndTraverse(grammar, 'thesuperm')
expect(options).to.eql([{
text: null,
words: [
{text: 'the', input: true},
{text: 'super', input: true},
{text: 'm', input: true},
{text: 'an', input: false}
],
result: {},
score: 1,
qualifiers: [],
categories: [],
arguments: [],
annotations:[],
data: []
}])
options = compileAndTraverse(grammar, 'thesuperman')
expect(options).to.eql([{
text: '',
words: [
{text: 'the', input: true},
{text: 'super', input: true},
{text: 'man', input: true}
],
result: {},
score: 1,
qualifiers: [],
categories: [],
arguments: [],
annotations:[],
data: []
}, {
text: null,
words: [
{text: 'the', input: true},
{text: 'super', input: true},
{text: 'man', input: true},
{text: 'rocks', input: false}
],
result: {},
score: 1,
categories: [],
arguments: [],
qualifiers: [],
annotations:[],
data: []
}])
options = compileAndTraverse(grammar, 'thesupermanr')
expect(options).to.eql([{
text: null,
words: [
{text: 'the', input: true},
{text: 'super', input: true},
{text: 'man', input: true},
{text: 'r', input: true},
{text: 'ocks', input: false}
],
result: {},
score: 1,
qualifiers: [],
categories: [],
arguments: [],
annotations:[],
data: []
}])
})
it('handles an optional child that is preferred', () => {
const grammar = (
<sequence>
<literal text='super' />
<literal text=' ' optional preferred />
<literal text='man' />
</sequence>
)
const options = compileAndTraverse(grammar, '')
expect(options).to.eql([{
text: null,
words: [
{text: 'super', input: false},
{text: ' ', input: false},
{text: 'man', input: false}
],
result: {},
score: 1,
categories: [],
arguments: [],
qualifiers: [],
annotations:[],
data: []
}, {
text: null,
words: [
{text: 'super', input: false},
{text: 'man', input: false}
],
result: {},
score: 1,
categories: [],
arguments: [],
qualifiers: [],
annotations:[],
data: []
}])
})
it('handles an optional child that is limited', () => {
const grammar = (
<sequence>
<literal text='super' />
<literal text=' ' optional limited />
<literal text='man' />
</sequence>
)
const options = compileAndTraverse(grammar, '')
expect(options).to.eql([{
text: null,
words: [
{text: 'super', input: false},
{text: 'man', input: false}
],
result: {},
score: 1,
qualifiers: [],
categories: [],
arguments: [],
annotations:[],
data: []
}])
})
it('handles an optional child that is limited with a list after', () => {
const grammar = (
<sequence>
<literal text='super' />
<literal text=' ' optional limited />
<list items={['man', 'maiden']} />
</sequence>
)
const options = compileAndTraverse(grammar, '')
expect(options).to.eql([{
text: null,
words: [
{text: 'super', input: false},
{text: 'man', input: false}
],
result: {},
score: 1,
qualifiers: [],
categories: [],
arguments: [],
annotations:[],
data: []
}, {
text: null,
words: [
{text: 'super', input: false},
{text: 'maiden', input: false}
],
result: {},
score: 1,
qualifiers: [],
categories: [],
arguments: [],
annotations:[],
data: []
}])
})
it('handles an optional child that is preferred and limited', () => {
const grammar = (
<sequence>
<literal text='super' />
<literal text=' ' optional preferred limited />
<literal text='man' />
</sequence>
)
const options = compileAndTraverse(grammar, '')
expect(options).to.eql([{
text: null,
words: [
{text: 'super', input: false},
{text: ' ', input: false},
{text: 'man', input: false}
],
result: {},
score: 1,
categories: [],
arguments: [],
qualifiers: [],
annotations:[],
data: []
}])
})
it('handles an optional child that is a sequence', () => {
const grammar = (
<sequence>
<literal text='super' />
<sequence optional>
<literal text='man' />
<literal text='again' />
</sequence>
</sequence>
)
const options = compileAndTraverse(grammar, 'superm')
expect(options).to.eql([{
text: null,
words: [
{text: 'super', input: true},
{text: 'm', input: true},
{text: 'an', input: false},
{text: 'again', input: false}
],
result: {},
score: 1,
qualifiers: [],
categories: [],
arguments: [],
annotations:[],
data: []
}])
})
it('handles an optional child that is a sequence with freetexts', () => {
const grammar = (
<sequence>
<freetext limit={1} />
<sequence optional>
<literal text='man' />
<freetext limit={1} />
<literal text='returns' />
</sequence>
</sequence>
)
const options = compileAndTraverse(grammar, 'supermanagainret')
expect(options).to.eql([{
text: null,
words: [
{text: 'super', input: true},
{text: 'man', input: true},
{text: 'again', input: true},
{text: 'ret', input: true},
{text: 'urns', input: false}
],
result: {},
score: options[0].score,
qualifiers: [],
categories: [],
arguments: [],
annotations:[],
data: []
}])
})
it('does not take an optional childs value', () => {
const grammar = (
<sequence>
<literal text='super' />
<literal text=' ' value='someValue' id='opt' optional />
<literal text='man' />
</sequence>
)
const options = compileAndTraverse(grammar, '')
expect(options).to.eql([{
text: null,
words: [
{text: 'super', input: false},
{text: 'man', input: false}
],
result: {},
score: 1,
qualifiers: [],
categories: [],
arguments: [],
annotations:[],
data: []
}, {
text: null,
words: [
{text: 'super', input: false},
{text: ' ', input: false},
{text: 'man', input: false}
],
result: {opt: 'someValue'},
score: 1,
qualifiers: [],
categories: [],
arguments: [],
annotations:[],
data: []
}])
})
it('can set a value to the result', () => {
const grammar = (
<sequence value='testValue'>
<literal text='super' />
<literal text='man' />
</sequence>
)
const options = compileAndTraverse(grammar, '')
expect(options).to.eql([{
text: null,
words: [
{text: 'super', input: false},
{text: 'man', input: false}
],
result: 'testValue',
score: 1,
qualifiers: [],
categories: [],
arguments: [],
annotations:[],
data: []
}])
})
it('will merge results in', () => {
const grammar = (
<sequence>
<literal id='desc' text='super' value='super' />
<sequence merge='true'>
<literal id='noun' text='man' value='man' />
<literal id='adj' text='rocks' value='rocks' />
</sequence>
</sequence>
)
const options = compileAndTraverse(grammar, '')
expect(options).to.eql([{
text: null,
words: [
{text: 'super', input: false},
{text: 'man', input: false},
{text: 'rocks', input: false}
],
result: {desc: 'super', noun: 'man', adj: 'rocks'},
score: 1,
qualifiers: [],
categories: [],
arguments: [],
annotations:[],
data: []
}])
})
it('will assign for non-object merge results', () => {
const grammar = (
<sequence>
<literal text='super' />
<literal text='man' value='man' merge />
</sequence>
)
const options = compileAndTraverse(grammar, '')
expect(options).to.eql([{
text: null,
words: [
{text: 'super', input: false},
{text: 'man', input: false}
],
result: 'man',
score: 1,
qualifiers: [],
categories: [],
arguments: [],
annotations:[],
data: []
}])
})
it('will merge results in for optionals', () => {
const grammar = (
<sequence>
<literal text='super' />
<literal text='man' value='man' optional merge />
</sequence>
)
const options = compileAndTraverse(grammar, '')
expect(options).to.eql([{
text: null,
words: [
{text: 'super', input: false}
],
result: {},
score: 1,
qualifiers: [],
categories: [],
arguments: [],
annotations:[],
data: []
}, {
text: null,
words: [
{text: 'super', input: false},
{text: 'man', input: false}
],
result: 'man',
score: 1,
qualifiers: [],
categories: [],
arguments: [],
annotations:[],
data: []
}])
})
it('checks for uniqueness', () => {
const grammar = (
<sequence unique>
<literal text='test' optional id='test' value={1} />
<literal text='a' />
<literal text='test' optional id='test' value={2} />
</sequence>
)
let options
options = compileAndTraverse(grammar, 'testa')
expect(options).to.eql([{
text: '',
words: [
{text: 'test', input: true},
{text: 'a', input: true}
],
result: {test: 1},
score: 1,
qualifiers: [],
categories: [],
arguments: [],
annotations:[],
data: []
}])
options = compileAndTraverse(grammar, 'atest')
expect(options).to.eql([{
text: '',
words: [
{text: 'a', input: true},
{text: 'test', input: true}
],
result: {test: 2},
score: 1,
qualifiers: [],
categories: [],
arguments: [],
annotations:[],
data: []
}])
options = compileAndTraverse(grammar, 'testatest')
expect(options).to.eql([])
})
it('allows for uniqueness in merges', () => {
const grammar = (
<sequence unique>
<literal text='test' optional id='test' value={1} />
<literal text='a' />
<literal text='test' optional merge value={{test: 2}} />
</sequence>
)
let options
options = compileAndTraverse(grammar, 'testa')
expect(options).to.eql([{
text: '',
words: [
{text: 'test', input: true},
{text: 'a', input: true}
],
result: {test: 1},
score: 1,
qualifiers: [],
categories: [],
arguments: [],
annotations:[],
data: []
}])
options = compileAndTraverse(grammar, 'atest')
expect(options).to.eql([{
text: '',
words: [
{text: 'a', input: true},
{text: 'test', input: true}
],
result: {test: 2},
score: 1,
qualifiers: [],
categories: [],
arguments: [],
annotations:[],
data: []
}])
options = compileAndTraverse(grammar, 'testatest')
expect(options).to.eql([])
})
it('does not emit if empty', () => {
const grammar = <sequence></sequence>
const options = compileAndTraverse(grammar, '')
expect(options).to.eql([])
})
})