import 'mocha' import { expect } from 'chai' import { getParseTreeFromString, getFunctionTreeFromDirective } from './helpers'; import { RangeNode, TrailNode, PeriodNode, RelativeExpressionNode, TimestampNode, RelativeTokenNode } from '../ast-nodes'; describe("FunctionFactory", function() { describe("Basic Functionality", function() { it("should allow custom defined 'now'", function(){ let tree = getParseTreeFromString("$range$0$now$"); let func = getFunctionTreeFromDirective(tree, 150) expect(func.End.anchor.solve()).to.be.equal(150) }) }) describe("Range Function", function() { it("should produce a RangeNode", function() { let tree = getParseTreeFromString("$range$0$now$"); let func = getFunctionTreeFromDirective(tree) expect(func).to.be.instanceOf(RangeNode) }) it("should have the correct start and end nodes", function() { let tree = getParseTreeFromString("$range$111$999$"); let func = getFunctionTreeFromDirective(tree) expect(func).to.be.eql( new RangeNode( new RelativeExpressionNode(new TimestampNode(111)), new RelativeExpressionNode(new TimestampNode(999)) ) ) }) it("should have the correct start and end nodes (now reference)", function() { let tree = getParseTreeFromString("$range$111$now$"); let func = getFunctionTreeFromDirective(tree, 999) expect(func).to.be.eql( new RangeNode( new RelativeExpressionNode(new TimestampNode(111)), new RelativeExpressionNode(new TimestampNode(999)) ) ) }) it("should have the correct start and end nodes (static expression)", function() { let tree = getParseTreeFromString("$range$111-1s$now+1s$"); let func = getFunctionTreeFromDirective(tree, 999) expect(func).to.be.eql( new RangeNode( new RelativeExpressionNode(new TimestampNode(110)), new RelativeExpressionNode(new TimestampNode(1000)) ) ) }) it("should have the correct start and end nodes (relative expression)", function() { let tree = getParseTreeFromString("$range$111-1Q$now+1Y$"); let func = getFunctionTreeFromDirective(tree, 999) expect(func).to.be.eql( new RangeNode( new RelativeExpressionNode(new TimestampNode(111), new RelativeTokenNode('Q', -1)), new RelativeExpressionNode(new TimestampNode(999), new RelativeTokenNode('Y', 1)) ) ) }) it("should solve to correct timestamp range (static)", function() { let tree = getParseTreeFromString("$range$1561872660$1561872880$"); let func = getFunctionTreeFromDirective(tree) expect(func.solve()).to.be.eql([1561872660, 1561872880]) }) }) describe("Trail Function", function() { it("should produce a TraiNode", function() { let tree = getParseTreeFromString("$trail$now$5m$"); let func = getFunctionTreeFromDirective(tree) expect(func).to.be.instanceOf(TrailNode) }) it("should have the correct end and period nodes", function() { let tree = getParseTreeFromString("$trail$111$5m$"); let func = getFunctionTreeFromDirective(tree) expect(func).to.be.eql( new TrailNode( new RelativeExpressionNode(new TimestampNode(111)), new RelativeExpressionNode(new TimestampNode(5*60*1)) ) ) }) it("should have the correct end and period nodes (relative)", function() { let tree = getParseTreeFromString("$trail$1561872660$1Q$"); let func = getFunctionTreeFromDirective(tree) expect(func).to.be.eql( new TrailNode( new RelativeExpressionNode(new TimestampNode(1561872660)), new RelativeTokenNode('Q', 1) ) ) expect(func.solve()).to.be.eql([1553923860, 1561872660]) }) it("should lead if the provided trail is negative", function() { let tree = getParseTreeFromString("$trail$1553923860$-1Q$"); let func = getFunctionTreeFromDirective(tree) expect(func.solve()).to.be.eql([1553923860, 1561872660]) }) it("should solve to correct timestamp range (static)", function() { let tree = getParseTreeFromString("$trail$1561872660$60$"); let func = getFunctionTreeFromDirective(tree) expect(func.solve()).to.be.eql([1561872600, 1561872660]) }) it("should solve to correct timestamp range (relative)", function() { let tree = getParseTreeFromString("$trail$1561872660$1Q$"); let func = getFunctionTreeFromDirective(tree) expect(func.solve()).to.be.eql([1553923860, 1561872660]) }) }) describe("Period Function", function() { it("should produce a PeriodNode", function() { let tree = getParseTreeFromString("$period$now$5m$"); let func = getFunctionTreeFromDirective(tree) expect(func).to.be.instanceOf(PeriodNode) }) it("should produce a PeriodNode when given ref", function() { let tree = getParseTreeFromString("$period$now$5Q$now$"); let func = getFunctionTreeFromDirective(tree) expect(func).to.be.instanceOf(PeriodNode) }) it("should solve to the correct timestamp range (first +ve period, static)", function() { let tree = getParseTreeFromString("$period$1561872660$10s$"); let func = getFunctionTreeFromDirective(tree, 1561872661) expect(func.solve()).to.be.eql([1561872660, 1561872670]) }) it("should solve to the correct timestamp range (first -ve period, static)", function() { let tree = getParseTreeFromString("$period$1561872660$10s$"); let func = getFunctionTreeFromDirective(tree, 1561872659) expect(func.solve()).to.be.eql([1561872650, 1561872660]) }) it("should solve to the correct timestamp range (nth +ve period, static, on boundary)", function() { let tree = getParseTreeFromString("$period$1561872660$10s$"); let func = getFunctionTreeFromDirective(tree, 1561872690) expect(func.solve()).to.be.eql([1561872680, 1561872690]) }) it("should solve to the correct timestamp range (first +ve period, relative)", function() { let tree = getParseTreeFromString("$period$1561872660$1Q$"); let func = getFunctionTreeFromDirective(tree, 1561872800) expect(func.solve()).to.be.eql([1561872660, 1569821460]) }) it("should solve to the correct timestamp range (nth +ve period, relative)", function() { let tree = getParseTreeFromString("$period$1561872660$1Q$"); let func = getFunctionTreeFromDirective(tree, 1569821461) expect(func.solve()).to.be.eql([1569821460, 1577683860]) }) it("should solve to the correct timestamp range (nth +ve period, relative, adjusted ref)", function() { let tree = getParseTreeFromString("$period$1561872660$1Q$now-5m$"); let func = getFunctionTreeFromDirective(tree, 1569821461) expect(func.solve()).to.be.eql([1561872660, 1569821460]) }) }) describe("Relative Expression Node", function() { it("should solve to a correct timestamp node when given no relative", function(){ var anchor = new TimestampNode(13579) var node = new RelativeExpressionNode(anchor) expect(node.solve()).to.be.eql(13579) }) it("should properly traverse 0 months", function(){ var anchor = new TimestampNode(+Date.UTC(2019,4,15,5,30)/1000) var relative = new RelativeTokenNode('M', 0) var node = new RelativeExpressionNode(anchor, relative) expect(node.solve()).to.be.eql(+Date.UTC(2019,4,15,5,30)/1000) }) it("should properly traverse 0 quarters", function(){ var anchor = new TimestampNode(+Date.UTC(2019,4,15,5,30)/1000) var relative = new RelativeTokenNode('Q', 0) var node = new RelativeExpressionNode(anchor, relative) expect(node.solve()).to.be.eql(+Date.UTC(2019,4,15,5,30)/1000) }) it("should properly traverse 0 years", function(){ var anchor = new TimestampNode(+Date.UTC(2019,4,15,5,30)/1000) var relative = new RelativeTokenNode('Y', 0) var node = new RelativeExpressionNode(anchor, relative) expect(node.solve()).to.be.eql(+Date.UTC(2019,4,15,5,30)/1000) }) it("should properly traverse back 1 month", function(){ var anchor = new TimestampNode(+Date.UTC(2019,4,15,5,30)/1000) var relative = new RelativeTokenNode('M', -1) var node = new RelativeExpressionNode(anchor, relative) expect(node.solve()).to.be.eql(+Date.UTC(2019,3,15,5,30)/1000) }) it("should properly traverse forward 1 month", function(){ var anchor = new TimestampNode(+Date.UTC(2019,4,15,5,30)/1000) var relative = new RelativeTokenNode('M', 1) var node = new RelativeExpressionNode(anchor, relative) expect(node.solve()).to.be.eql(+Date.UTC(2019,5,15,5,30)/1000) }) it("should properly traverse back n months (within year)", function(){ var anchor = new TimestampNode(+Date.UTC(2019,4,15,5,30)/1000) var relative = new RelativeTokenNode('M', -4) var node = new RelativeExpressionNode(anchor, relative) expect(node.solve()).to.be.eql(+Date.UTC(2019,0,15,5,30)/1000) }) it("should properly traverse back n months (across year)", function(){ var anchor = new TimestampNode(+Date.UTC(2019,4,15,5,30)/1000) var relative = new RelativeTokenNode('M', -6) var node = new RelativeExpressionNode(anchor, relative) expect(node.solve()).to.be.eql(+Date.UTC(2018,10,15,5,30)/1000) }) it("should properly traverse back n months (across year && > 12)", function(){ var anchor = new TimestampNode(+Date.UTC(2019,4,15,5,30)/1000) var relative = new RelativeTokenNode('M', -25) var node = new RelativeExpressionNode(anchor, relative) expect(node.solve()).to.be.eql(+Date.UTC(2017,3,15,5,30)/1000) }) it("should properly traverse forward n months (within year)", function(){ var anchor = new TimestampNode(+Date.UTC(2019,4,15,5,30)/1000) var relative = new RelativeTokenNode('M', 4) var node = new RelativeExpressionNode(anchor, relative) expect(node.solve()).to.be.eql(+Date.UTC(2019,8,15,5,30)/1000) }) it("should properly traverse forward n months (across year)", function(){ var anchor = new TimestampNode(+Date.UTC(2019,4,15,5,30)/1000) var relative = new RelativeTokenNode('M', 10) var node = new RelativeExpressionNode(anchor, relative) expect(node.solve()).to.be.eql(+Date.UTC(2020,2,15,5,30)/1000) }) it("should properly traverse forward n months (across year && > 12)", function(){ var anchor = new TimestampNode(+Date.UTC(2019,4,15,5,30)/1000) var relative = new RelativeTokenNode('M', 25) var node = new RelativeExpressionNode(anchor, relative) expect(node.solve()).to.be.eql(+Date.UTC(2021,5,15,5,30)/1000) }) it("(0) should be conservative when traversing back to a non-existant date by months", function(){ var anchor_0 = new TimestampNode(+Date.UTC(2019,2,29,5,30)/1000) var anchor_1 = new TimestampNode(+Date.UTC(2019,2,30,5,30)/1000) var anchor_2 = new TimestampNode(+Date.UTC(2019,2,31,5,30)/1000) var relative = new RelativeTokenNode('M', -1) var node_0 = new RelativeExpressionNode(anchor_0, relative) var node_1 = new RelativeExpressionNode(anchor_1, relative) var node_2 = new RelativeExpressionNode(anchor_2, relative) expect(node_0.solve()).to.be.eql(+Date.UTC(2019,2,1,5,30)/1000) expect(node_1.solve()).to.be.eql(+Date.UTC(2019,2,1,5,30)/1000) expect(node_2.solve()).to.be.eql(+Date.UTC(2019,2,1,5,30)/1000) }) it("(1) should be conservative when traversing back to a non-existant date by months", function(){ var anchor = new TimestampNode(+Date.UTC(2019,4,31,5,30)/1000) var relative = new RelativeTokenNode('M', -1) var node = new RelativeExpressionNode(anchor, relative) expect(node.solve()).to.be.eql(+Date.UTC(2019,4,1,5,30)/1000) }) it("(0) should be conservative when traversing forward to a non-existant date by months", function(){ var anchor_0 = new TimestampNode(+Date.UTC(2019,0,29,5,30)/1000) var anchor_1 = new TimestampNode(+Date.UTC(2019,0,30,5,30)/1000) var anchor_2 = new TimestampNode(+Date.UTC(2019,0,31,5,30)/1000) var relative = new RelativeTokenNode('M', 1) var node_0 = new RelativeExpressionNode(anchor_0, relative) var node_1 = new RelativeExpressionNode(anchor_1, relative) var node_2 = new RelativeExpressionNode(anchor_2, relative) expect(node_0.solve()).to.be.eql(+Date.UTC(2019,1,28,5,30)/1000) expect(node_1.solve()).to.be.eql(+Date.UTC(2019,1,28,5,30)/1000) expect(node_2.solve()).to.be.eql(+Date.UTC(2019,1,28,5,30)/1000) }) it("(1) should be conservative when traversing forward to a non-existant date by months", function(){ var anchor = new TimestampNode(+Date.UTC(2019,4,31,5,30)/1000) var relative = new RelativeTokenNode('M', 1) var node = new RelativeExpressionNode(anchor, relative) expect(node.solve()).to.be.eql(+Date.UTC(2019,5,30,5,30)/1000) }) it("should properly traverse back 1 year", function(){ var anchor = new TimestampNode(+Date.UTC(2019,4,15,5,30)/1000) var relative = new RelativeTokenNode('Y', -1) var node = new RelativeExpressionNode(anchor, relative) expect(node.solve()).to.be.eql(+Date.UTC(2018,4,15,5,30)/1000) }) it("should properly traverse forward 1 year", function(){ var anchor = new TimestampNode(+Date.UTC(2019,4,15,5,30)/1000) var relative = new RelativeTokenNode('Y', 1) var node = new RelativeExpressionNode(anchor, relative) expect(node.solve()).to.be.eql(+Date.UTC(2020,4,15,5,30)/1000) }) it("should properly traverse back n years", function(){ var anchor = new TimestampNode(+Date.UTC(2019,4,15,5,30)/1000) var relative = new RelativeTokenNode('Y', -4) var node = new RelativeExpressionNode(anchor, relative) expect(node.solve()).to.be.eql(+Date.UTC(2015,4,15,5,30)/1000) }) it("should properly traverse forward n years", function(){ var anchor = new TimestampNode(+Date.UTC(2019,4,15,5,30)/1000) var relative = new RelativeTokenNode('Y', 4) var node = new RelativeExpressionNode(anchor, relative) expect(node.solve()).to.be.eql(+Date.UTC(2023,4,15,5,30)/1000) }) it("(0) should be conservative when traversing back to a non-existant date by years", function(){ var anchor = new TimestampNode(+Date.UTC(2020,1,29,5,30)/1000) var relative = new RelativeTokenNode('Y', -1) var node = new RelativeExpressionNode(anchor, relative) expect(node.solve()).to.be.eql(+Date.UTC(2019,2,1,5,30)/1000) }) it("(1) should be conservative when traversing forward to a non-existant date by years", function(){ var anchor = new TimestampNode(+Date.UTC(2020,1,29,5,30)/1000) var relative = new RelativeTokenNode('Y', 1) var node = new RelativeExpressionNode(anchor, relative) expect(node.solve()).to.be.eql(+Date.UTC(2021,1,28,5,30)/1000) }) it("should properly traverse back 1 quarter", function(){ var anchor = new TimestampNode(+Date.UTC(2019,4,15,5,30)/1000) var relative = new RelativeTokenNode('Q', -1) var node = new RelativeExpressionNode(anchor, relative) expect(node.solve()).to.be.eql(+Date.UTC(2019,1,15,5,30)/1000) }) it("should properly traverse forward 1 quarter", function(){ var anchor = new TimestampNode(+Date.UTC(2019,4,15,5,30)/1000) var relative = new RelativeTokenNode('Q', 1) var node = new RelativeExpressionNode(anchor, relative) expect(node.solve()).to.be.eql(+Date.UTC(2019,7,15,5,30)/1000) }) it("should properly traverse back n quarters", function(){ var anchor = new TimestampNode(+Date.UTC(2019,4,15,5,30)/1000) var relative = new RelativeTokenNode('Q', -3) var node = new RelativeExpressionNode(anchor, relative) expect(node.solve()).to.be.eql(+Date.UTC(2018,7,15,5,30)/1000) }) it("should properly traverse forward n quarters", function(){ var anchor = new TimestampNode(+Date.UTC(2019,4,15,5,30)/1000) var relative = new RelativeTokenNode('Q', 3) var node = new RelativeExpressionNode(anchor, relative) expect(node.solve()).to.be.eql(+Date.UTC(2020,1,15,5,30)/1000) }) it("(0) should be conservative when traversing back to a non-existant date by quarters", function(){ var anchor = new TimestampNode(+Date.UTC(2019,4,29,5,30)/1000) var relative = new RelativeTokenNode('Q', -1) var node = new RelativeExpressionNode(anchor, relative) expect(node.solve()).to.be.eql(+Date.UTC(2019,2,1,5,30)/1000) }) it("(1) should be conservative when traversing forward to a non-existant date by quarters", function(){ var anchor = new TimestampNode(+Date.UTC(2018,10,29,5,30)/1000) var relative = new RelativeTokenNode('Q', 1) var node = new RelativeExpressionNode(anchor, relative) expect(node.solve()).to.be.eql(+Date.UTC(2019,1,28,5,30)/1000) }) }) })