UNPKG

ng-tql

Version:

A domain specific language that extends SQL and allows visual metaprogramming

167 lines (138 loc) 6.03 kB
const expect = require('chai').expect; const tql = require('../dist/tql'); describe('Parser specification', () => { describe('Inferred type declarations', () => { it('Shouldn\'t support free-type variables', () => { expect(() => tql.parse('Declare Age')).to.throw(TypeError, /Cannot infer type of free variable/); }); it('Should infer integers', () => { const ast = tql.parse('Declare Age := 18'); expect(ast[0].type[0]).to.be.equal('int'); }); it('Should infer doubles', () => { const ast = tql.parse('Declare Price := 10.5'); expect(ast[0].type[0]).to.be.equal('double'); }); it('Should infer symbols', () => { const ast = tql.parse('Declare Table := STJT30'); expect(ast[0].type[0]).to.be.equal('symbol'); }); it('Should infer any char(*) to varchar', () => { const ast = tql.parse('Declare Username := \'Admin\''); expect(ast[0].type[0]).to.be.equal('varchar'); }); it('Should infer booleans', () => { const ast = tql.parse('Declare ShouldUpdate := .F.'); expect(ast[0].type[0]).to.be.equal('bool'); }); }); describe('Type declarations' , () => { it('Should allow every type to have defined variables without value', () => { const source = [ 'Declare Val: Int', 'Declare Name: VarChar', 'Declare When: Date', 'Declare Age: Nat', 'Declare Trigger: Bool', 'Declare Table: Symbol', 'Declare Id: Char(32)', 'Declare Limit: Range(10, 100)', 'Declare Price: Double' ]; tql.parse(source.join('\n')); }); it('Should restrict negative numbers on Nat', () => { expect(() => { tql.parse('Declare Age: Nat := -10'); }).to.throw(TypeError, /Value of type `int\(-10\)' is not assignable to field of type `nat'/); }); it('Should restrict max length of string in Char(*)', () => { expect(() => { tql.parse('Declare Val: Char(10) := \'Trixie Mattel\''); }).to.throw(TypeError, /Value of type `string\(13\)' is not assignable to field of type `char\(10\)'/); }); it('Should restrict max number in Range(*, *)', () => { expect(() => { tql.parse('Declare Val: Range(1, 10) := 11'); }).to.throw(TypeError, /Value of type `int\(11\)' is not assignable to field of type `range\(1, 10\)'/); }); it('Should restrict min number in Range(*, *)', () => { expect(() => { tql.parse('Declare Val: Range(1, 10) := -20'); }).to.throw(TypeError, /Value of type `int\(-20\)' is not assignable to field of type `range\(1, 10\)'/); }); }); describe('Duplication', () => { it('Doesn\'t allow duplicated fields', () => { const source = [ 'Declare age := 18', 'Declare Age := .T.' ]; expect(() => { tql.parse(source.join('')); }).to.throw(Error, /Field `AGE' declared twice/); }); }); describe('Picture', () => { it('Allows pictures after type declaration', () => { tql.parse('Declare Price: Nat Picture \'99.99\' := 10'); }); it('Allows pictures after name declaration', () => { tql.parse('Declare Price Picture \'99.99\' := 10'); }); }); describe('Description', () => { it('Allows descriptions to be placed after all', () => { tql.parse('Declare Table: Symbol := STJT30 { Table to select }'); }); it('Allows descriptions with line break', () => { tql.parse('Declare Table: Symbol := STJT30 { Table\n to select }'); }); }); describe('Dates', () => { it('Should allow a date to be assigned to Date', () => { tql.parse('Declare BirthDay: Date := 4 Dec 1996'); }); it('Should reject negative day', () => { expect(() => { tql.parse('Declare BirthDay := -4 Dec 1996'); }).to.throw(Error, /Day of date must be positive/); }); it('Should reject negative year', () => { expect(() => { tql.parse('Declare BirthDay := 4 Dec -1996'); }).to.throw(Error, /Year of date must be positive/); }); it('Should allow seconds on datetime', () => { tql.parse('Declare ExactMoment := 7 Nov 2016 13:43:32'); }); it ('Should allow a datetime to be assigned to Date', () => { tql.parse('Declare Event: Date := 7 Nov 2016 13:30'); }); it('Should validate hours', () => { expect(() => { tql.parse('Declare Event: Date := 7 Nov 2016 -13:00'); }).to.throw(Error, /Hour of time must be between 0 and 23/); }); it('Should validate minutes', () => { expect(() => { tql.parse('Declare Event: Date := 7 Nov 2016 13:78'); }).to.throw(Error, /Minute of time must be between 0 and 59/); }); it('Should validate seconds', () => { expect(() => { tql.parse('Declare Event: Date := 7 Nov 2016 13:10:61'); }).to.throw(Error, /Seconds of time must be between 0 and 59/); }); }); describe('Syntax', () => { it('Should be case insensitive for keywords', () => { const lower = tql.parse('declare X: int := 1'); const upper = tql.parse('Declare X: Int := 1'); expect(lower).to.be.deep.equal(upper); }); it('Shouldn\'t care about whitespace', () => { tql.parse(' declare Foo:Date:=18 Dec 1887 '); }); }); });