elliptical
Version:
Interactive natural-language interfaces
539 lines (495 loc) • 12.8 kB
JSX
/** @jsx createElement */
/* eslint-env mocha */
import createElement from '../src/element'
import unique from '../src/unique'
import {compileAndTraverse} from './_util'
import { expect } from 'chai'
describe('repeat', () => {
describe('separator', () => {
it('does not accept input that does not match the child', () => {
const grammar = (
<repeat separator={<literal text='man' />}>
<literal text='super' />
</repeat>
)
const options = compileAndTraverse(grammar, 'wrong')
expect(options).to.eql([])
})
it('accepts the child on its own', () => {
const grammar = (
<repeat separator={<literal text='man' />}>
<literal text='super' />
</repeat>
)
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: 'super', input: false}
],
result: [undefined, undefined],
score: 1,
qualifiers: [],
categories: [],
arguments: [],
annotations:[],
data: []
}])
})
it('accepts the child twice, with the separator in the middle', () => {
const grammar = (
<repeat separator={<literal text='man' />}>
<literal text='super' />
</repeat>
)
const options = compileAndTraverse(grammar, 'supermans')
expect(options).to.eql([{
text: null,
words: [
{text: 'super', input: true},
{text: 'man', input: true},
{text: 's', input: true},
{text: 'uper', input: false}
],
result: [undefined, undefined],
score: 1,
qualifiers: [],
categories: [],
arguments: [],
annotations:[],
data: []
}])
})
it('accepts the child twice and suggests when complete, with the separator in the middle', () => {
const grammar = (
<repeat separator={<literal text='man' />}>
<literal text='super' />
</repeat>
)
const options = compileAndTraverse(grammar, 'supermansuper')
expect(options).to.eql([{
text: '',
words: [
{text: 'super', input: true},
{text: 'man', input: true},
{text: 'super', input: true}
],
result: [undefined, undefined],
score: 1,
qualifiers: [],
categories: [],
arguments: [],
annotations:[],
data: []
}, {
text: null,
words: [
{text: 'super', input: true},
{text: 'man', input: true},
{text: 'super', input: true},
{text: 'man', input: false},
{text: 'super', input: false}
],
result: [undefined, undefined, undefined],
score: 1,
qualifiers: [],
categories: [],
arguments: [],
annotations:[],
data: []
}])
})
it('allows for content to have children', () => {
const grammar = (
<repeat separator={<literal text=' ' />}>
<choice>
<literal text='a' />
<literal text='b' />
</choice>
</repeat>
)
const options = compileAndTraverse(grammar, 'a ')
expect(options).to.eql([{
text: null,
words: [
{text: 'a', input: true},
{text: ' ', input: true},
{text: 'a', input: false}
],
result: [undefined, undefined],
score: 1,
qualifiers: [],
categories: [],
arguments: [],
annotations:[],
data: []
}, {
text: null,
words: [
{text: 'a', input: true},
{text: ' ', input: true},
{text: 'b', input: false}
],
result: [undefined, undefined],
score: 1,
qualifiers: [],
categories: [],
arguments: [],
annotations:[],
data: []
}])
})
})
it('allows for content to have children', () => {
const grammar = (
<repeat>
<choice>
<literal text='a' />
<literal text='b' />
</choice>
</repeat>
)
const options = compileAndTraverse(grammar, '')
expect(options).to.eql([{
text: null,
words: [{text: 'a', input: false}],
result: [undefined],
score: 1,
qualifiers: [],
categories: [],
arguments: [],
annotations:[],
data: []
}, {
text: null,
words: [{text: 'b', input: false}],
result: [undefined],
score: 1,
qualifiers: [],
categories: [],
arguments: [],
annotations:[],
data: []
}])
})
it('does not accept input that does not match the child', () => {
const grammar = (
<repeat>
<literal text='super' />
</repeat>
)
const options = compileAndTraverse(grammar, 'wrong')
expect(options).to.eql([])
})
it('accepts the child on its own', () => {
const grammar = (
<repeat>
<literal text='super' value='a' />
</repeat>
)
const options = compileAndTraverse(grammar, 'sup')
expect(options).to.eql([{
text: null,
words: [{text: 'sup', input: true}, {text: 'er', input: false}],
result: ['a'],
score: 1,
qualifiers: [],
categories: [],
arguments: [],
annotations:[],
data: []
}])
})
it('accepts the child twice', () => {
const grammar = (
<repeat>
<literal text='super' value='a' />
</repeat>
)
const options = compileAndTraverse(grammar, 'supers')
expect(options).to.eql([{
text: null,
words: [
{text: 'super', input: true},
{text: 's', input: true},
{text: 'uper', input: false}
],
result: ['a', 'a'],
score: 1,
qualifiers: [],
categories: [],
arguments: [],
annotations:[],
data: []
}])
})
it('accepts the child thrice', () => {
const grammar = (
<repeat>
<literal text='super' value='a' />
</repeat>
)
const options = compileAndTraverse(grammar, 'supersuper')
expect(options).to.eql([{
text: '',
words: [
{text: 'super', input: true},
{text: 'super', input: true}
],
result: ['a', 'a'],
score: 1,
qualifiers: [],
categories: [],
arguments: [],
annotations:[],
data: []
}, {
text: null,
words: [
{text: 'super', input: true},
{text: 'super', input: true},
{text: 'super', input: false}
],
result: ['a', 'a', 'a'],
score: 1,
categories: [],
arguments: [],
qualifiers: [],
annotations:[],
data: []
}])
})
it('does not accept fewer than min iterations', () => {
const grammar = (
<repeat min={2}>
<literal text='a' value='a' />
</repeat>
)
const options = compileAndTraverse(grammar, 'a')
expect(options).to.eql([{
text: null,
words: [
{text: 'a', input: true},
{text: 'a', input: false}
],
result: ['a', 'a'],
score: 1,
qualifiers: [],
categories: [],
arguments: [],
annotations:[],
data: []
}])
})
it('does not accept more than max iterations', () => {
const grammar = (
<repeat max={1} >
<literal text='a' value='a' />
</repeat>
)
const options = compileAndTraverse(grammar, 'a')
expect(options).to.eql([{
text: '',
words: [
{text: 'a', input: true}
],
result: ['a'],
score: 1,
qualifiers: [],
categories: [],
arguments: [],
annotations:[],
data: []
}])
})
it('unique rejects non-unique repeated elements', () => {
const grammar = (
<repeat unique>
<choice>
<literal text='a' value='1' />
<literal text='b' value='1' />
</choice>
</repeat>
)
const options = compileAndTraverse(grammar, 'ab')
expect(options).to.eql([])
})
it('unique rejects non-unique repeated elements (using symbol)', () => {
const grammar = (
<repeat unique>
<choice>
<literal text='a' value={{val: 1, [unique]: 'test'}} />
<literal text='b' value={{val: 2, [unique]: 'test'}} />
</choice>
</repeat>
)
const options = compileAndTraverse(grammar, 'ab')
expect(options).to.eql([])
})
it('unique accepts non-unique repeated elements (using symbol)', () => {
const grammar = (
<repeat unique>
<choice>
<literal text='a' value={{val: 2, [unique]: '1'}} />
<literal text='b' value={{val: 2, [unique]: 'test'}} />
</choice>
</repeat>
)
const options = compileAndTraverse(grammar, 'ab')
expect(options).to.eql([{
text: '',
words: [
{text: 'a', input: true},
{text: 'b', input: true}
],
result: [{val: 2}, {val: 2}],
score: 1,
qualifiers: [],
categories: [],
arguments: [],
annotations:[],
data: []
}])
})
it('unique rejects non-unique repeated elements (deep)', () => {
const grammar = (
<repeat unique>
<choice>
<literal text='a' value={{a: 1}} />
<literal text='b' value={{a: 1}} />
</choice>
</repeat>
)
const options = compileAndTraverse(grammar, 'ab')
expect(options).to.eql([])
})
it('unique accepts unique repeated elements', () => {
const grammar = (
<repeat unique>
<choice>
<literal text='a' value='a' />
<literal text='b' value='b' />
</choice>
</repeat>
)
const options = compileAndTraverse(grammar, 'ab')
expect(options).to.eql([{
text: '',
words: [
{text: 'a', input: true},
{text: 'b', input: true}
],
result: ['a', 'b'],
score: 1,
qualifiers: [],
categories: [],
arguments: [],
annotations:[],
data: []
}])
})
it('unique accepts unique repeated elements (deep)', () => {
const grammar = (
<repeat unique>
<choice>
<literal text='a' value={{a: 1}} />
<literal text='b' value={{a: 2}} />
</choice>
</repeat>
)
const options = compileAndTraverse(grammar, 'ab')
expect(options).to.eql([{
text: '',
words: [
{text: 'a', input: true},
{text: 'b', input: true}
],
result: [{a: 1}, {a: 2}],
score: 1,
categories: [],
arguments: [],
qualifiers: [],
annotations:[],
data: []
}])
})
it('allows for choices inside of repeats to be limited', () => {
const grammar = (
<repeat>
<choice limit={1}>
<literal text='aa' />
<literal text='ab' />
<literal text='ac' />
</choice>
</repeat>
)
const options = compileAndTraverse(grammar, 'aba')
expect(options).to.eql([{
text: null,
words: [
{text: 'ab', input: true},
{text: 'a', input: true},
{text: 'a', input: false}
],
result: [undefined, undefined],
score: 1,
qualifiers: [],
categories: [],
arguments: [],
annotations:[],
data: []
}])
})
it('allows for choices inside of repeat separators to be limited', () => {
const grammar = (
<repeat separator={
<choice limit={1}>
<literal text='aa' />
<literal text='ab' />
<literal text='ac' />
</choice>
}>
<literal text='x' />
</repeat>
)
const options = compileAndTraverse(grammar, 'xa')
expect(options).to.eql([{
text: null,
words: [
{text: 'x', input: true},
{text: 'a', input: true},
{text: 'a', input: false},
{text: 'x', input: false}
],
result: [undefined, undefined],
score: 1,
qualifiers: [],
categories: [],
arguments: [],
annotations:[],
data: []
}])
})
it('works with data', () => {
const grammar = <repeat data={1}><literal text='x ' data={2} /></repeat>
const options = compileAndTraverse(grammar, 'x x')
expect(options).to.eql([{
text: null,
words: [
{text: 'x ', input: true},
{text: 'x', input: true},
{text: ' ', input: false},
],
result: [undefined, undefined],
score: 1,
qualifiers: [],
categories: [],
arguments: [],
annotations:[],
data: [1, 2, 2]
}])
})
})