UNPKG

dvbcss-clocks

Version:

Javascript library implementing clock objects for modelling timelines. Useful in DVB CSS implementations.

279 lines (223 loc) 12.2 kB
/**************************************************************************** * Copyright 2017 British Broadcasting Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. *****************************************************************************/ var CorrelatedClock = require("CorrelatedClock"); var DateNowClock = require("DateNowClock"); var Correlation = require("Correlation"); describe("For hierarchies of clocks", function() { it("when toOtherClockTime() is called, an error is thrown if the two clocks are not part of the same hierarchy (and therefore have no common ancestor)", function() { var a = new DateNowClock({tickRate:1000000}); var b = new DateNowClock({tickRate:1000000}); var a1 = new CorrelatedClock(a, {tickRate:1000,correlation:new Correlation(0,0)}); var b1 = new CorrelatedClock(b, {tickRate:1000,correlation:new Correlation(0,0)}); var a2 = new CorrelatedClock(a1, {tickRate:1000,correlation:new Correlation(0,0)}); var b2 = new CorrelatedClock(b1, {tickRate:1000,correlation:new Correlation(0,0)}); expect(function() { a.toOtherClockTime(b, 5); }).toThrow(); expect(function() { a.toOtherClockTime(b1, 5); }).toThrow(); expect(function() { a.toOtherClockTime(b2, 5); }).toThrow(); expect(function() { a1.toOtherClockTime(b, 5); }).toThrow(); expect(function() { a1.toOtherClockTime(b1, 5); }).toThrow(); expect(function() { a1.toOtherClockTime(b2, 5); }).toThrow(); expect(function() { a2.toOtherClockTime(b, 5); }).toThrow(); expect(function() { a2.toOtherClockTime(b1, 5); }).toThrow(); expect(function() { a2.toOtherClockTime(b2, 5); }).toThrow(); expect(function() { b.toOtherClockTime(a, 5); }).toThrow(); expect(function() { b.toOtherClockTime(a1, 5); }).toThrow(); expect(function() { b.toOtherClockTime(a2, 5); }).toThrow(); expect(function() { b1.toOtherClockTime(a, 5); }).toThrow(); expect(function() { b1.toOtherClockTime(a1, 5); }).toThrow(); expect(function() { b1.toOtherClockTime(a2, 5); }).toThrow(); expect(function() { b2.toOtherClockTime(a, 5); }).toThrow(); expect(function() { b2.toOtherClockTime(a1, 5); }).toThrow(); expect(function() { b2.toOtherClockTime(a2, 5); }).toThrow(); }); it("toOtherClockTime() can be used to convert to the parent's time", function() { var a = new DateNowClock({tickRate:1000000}); var a1 = new CorrelatedClock(a, {tickRate:100,correlation:new Correlation(50,0)}); var a2 = new CorrelatedClock(a1, {tickRate:78,correlation:new Correlation(38,999)}); expect(a1.toOtherClockTime(a, 500)).toEqual(a1.toParentTime(500)); expect(a2.toOtherClockTime(a1, 500)).toEqual(a2.toParentTime(500)); }); it("toOtherClockTime() can be used to convert to a parent's parent's time", function() { var a = new DateNowClock({tickRate:1000000}); var a1 = new CorrelatedClock(a, {tickRate:100,correlation:new Correlation(50,0)}); var a2 = new CorrelatedClock(a1, {tickRate:78,correlation:new Correlation(28,999)}); expect(a2.toOtherClockTime(a, 500)).toEqual( a1.toParentTime(a2.toParentTime(500)) ); }); it("toOtherClockTime() can be used to convert between ancestors in a linear hierarchy", function() { var a = new DateNowClock({tickRate:1000000}); var a1 = new CorrelatedClock(a, {tickRate:100,correlation:new Correlation(50,0)}); var a2 = new CorrelatedClock(a1, {tickRate:78,correlation:new Correlation(28,999)}); var a3 = new CorrelatedClock(a2, {tickRate:178,correlation:new Correlation(5,1003)}); var a4 = new CorrelatedClock(a3, {tickRate:28,correlation:new Correlation(17,9)}); expect(a3.toOtherClockTime(a1, 500)).toEqual( a2.toParentTime(a3.toParentTime(500)) ); }); it("toOtherClockTime() can be used to convert between clocks on different branches", function() { var a = new DateNowClock({tickRate:1000000}); var a1 = new CorrelatedClock(a, {tickRate:100,correlation:new Correlation(50,0)}); var a2 = new CorrelatedClock(a1, {tickRate:78,correlation:new Correlation(28,999)}); var a3 = new CorrelatedClock(a2, {tickRate:178,correlation:new Correlation(5,1003)}); var a4 = new CorrelatedClock(a3, {tickRate:28,correlation:new Correlation(17,9)}); var b3 = new CorrelatedClock(a2, {tickRate:1000,correlation:new Correlation(10,20)}); var b4 = new CorrelatedClock(b3, {tickRate:2000,correlation:new Correlation(15,90)}); var v = a4.toParentTime(500); v = a3.toParentTime(v); v = b3.fromParentTime(v); v = b4.fromParentTime(v); expect(a4.toOtherClockTime(b4,500)).toEqual(v); }); it("a change of speed propagates through the hierarchy and is reflected in getEffectiveSpeed()", function() { var datenow = spyOn(Date,"now"); datenow.and.returnValue(5000); var a = new DateNowClock({tickRate:1000}); var a1 = new CorrelatedClock(a, {tickRate:1000,correlation:new Correlation(50,0)}); var a2 = new CorrelatedClock(a1, {tickRate:100,correlation:new Correlation(28,999)}); var a3 = new CorrelatedClock(a2, {tickRate:50,correlation:new Correlation(5,1003)}); var a4 = new CorrelatedClock(a3, {tickRate:25,correlation:new Correlation(1000,9)}); var b3 = new CorrelatedClock(a2, {tickRate:1000,correlation:new Correlation(500,20)}); var b4 = new CorrelatedClock(b3, {tickRate:2000,correlation:new Correlation(15,90)}); var at1 = a.now(); var a1t1 = a1.now(); var a2t1 = a2.now(); var a3t1 = a3.now(); var a4t1 = a4.now(); var b3t1 = b3.now(); var b4t1 = b4.now(); a3.speed = 0.5; a4.speed = 0.2; expect(a.getEffectiveSpeed()).toEqual(1.0); expect(a1.getEffectiveSpeed()).toEqual(1.0); expect(a2.getEffectiveSpeed()).toEqual(1.0); expect(a3.getEffectiveSpeed()).toEqual(0.5); expect(a4.getEffectiveSpeed()).toEqual(0.1); a3.speed = 0; a4.speed = 1.0; expect(a.getEffectiveSpeed()).toEqual(1.0); expect(a1.getEffectiveSpeed()).toEqual(1.0); expect(a2.getEffectiveSpeed()).toEqual(1.0); expect(a3.getEffectiveSpeed()).toEqual(0.0); expect(a4.getEffectiveSpeed()).toEqual(0.0); datenow.and.returnValue(6000); var at2 = a.now(); var a1t2 = a1.now(); var a2t2 = a2.now(); var a3t2 = a3.now(); var a4t2 = a4.now(); var b3t2 = b3.now(); var b4t2 = b4.now(); expect(at2).toBeCloseTo(at1 + 1000, 5); expect(a1t2).toBeCloseTo(a1t1 + 1000, 5); expect(a2t2).toBeCloseTo(a2t1 + 100, 5); expect(a3t2).toBeCloseTo(1003, 5); expect(a4t2).toBeCloseTo(10.5, 5); expect(b3t2).toBeCloseTo(b3t1 + 1000, 5); expect(b4t2).toBeCloseTo(b4t1 + 2000, 5); }); it("propagates availability throuhg a hierarchy causing 'available' and 'unavailable' events when availability changes, but not causing 'change' events", function() { var a = new DateNowClock(); var b = new CorrelatedClock(a); var c = new CorrelatedClock(b); var d = new CorrelatedClock(c); var aa = jasmine.createSpy("aa"); var ab = jasmine.createSpy("ab"); var ac = jasmine.createSpy("ac"); var ad = jasmine.createSpy("ad"); var ca = jasmine.createSpy("ca"); var cb = jasmine.createSpy("cb"); var cc = jasmine.createSpy("cc"); var cd = jasmine.createSpy("cd"); var ua = jasmine.createSpy("ua"); var ub = jasmine.createSpy("ub"); var uc = jasmine.createSpy("uc"); var ud = jasmine.createSpy("ud"); a.on("available", aa); a.on("unavailable", ua); a.on("change", ca); b.on("available", ab); b.on("unavailable", ub); b.on("change", cb); c.on("available", ac); c.on("unavailable", uc); c.on("change", cc); d.on("available", ad); d.on("unavailable", ud); d.on("change", cd); expect(a.isAvailable()).toBeTruthy(); expect(b.isAvailable()).toBeTruthy(); expect(c.isAvailable()).toBeTruthy(); expect(d.isAvailable()).toBeTruthy(); c.availabilityFlag = false; expect(a.isAvailable()).toBeTruthy(); expect(b.isAvailable()).toBeTruthy(); expect(c.isAvailable()).toBeFalsy(); expect(d.isAvailable()).toBeFalsy(); [aa,ua,ca,ab,ub,cb,cc,ac,ad,cd].forEach(function(callback) { expect(callback).not.toHaveBeenCalled(); }); [uc,ud].forEach(function(callback) { expect(callback).toHaveBeenCalled(); callback.calls.reset(); }); d.availabilityFlag = false; [aa,ua,ca,ab,ub,cb,ac,uc,cc,ad,ud,cd].forEach(function(callback) { expect(callback).not.toHaveBeenCalled(); }); c.availabilityFlag = true; [aa,ua,ca,ab,ub,cb,cc,uc,cd,ad,ud].forEach(function(callback) { expect(callback).not.toHaveBeenCalled(); }); [ac].forEach(function(callback) { expect(callback).toHaveBeenCalled(); callback.calls.reset(); }); }); it("can still propagate availability changes even if availability is changed mid availablility change handler", function() { var unavailabilityListener = jasmine.createSpy("spy"); var a = new DateNowClock({tickRate:1000000}); var b = new CorrelatedClock(a, {tickRate:1000, correlation:new Correlation(0,0)}); var c = new CorrelatedClock(null, {tickRate:2000, correlation:new Correlation(0,0)}); b.on("unavailable", function() { c.availabilityFlag = false; }); c.setParent(b); c.on("unavailable", unavailabilityListener); b.availabilityFlag = false; expect(unavailabilityListener).toHaveBeenCalled(); }); it("can calculate a difference between two clocks using clockDiff() method", function() { var datenow = spyOn(Date,"now"); datenow.and.returnValue(1000); var a = new DateNowClock({tickRate:1000000}); var b = new CorrelatedClock(a, {tickRate:1000, correlation:new Correlation(0,0)}); var c = new CorrelatedClock(b, {tickRate:2000, correlation:new Correlation(0,0)}); var d = new CorrelatedClock(c, {tickRate:3000, correlation:new Correlation(0,0)}); var e = new CorrelatedClock(d, {tickRate:1000, correlation:new Correlation(5,0)}); expect(b.clockDiff(c)).toEqual(Number.POSITIVE_INFINITY); expect(b.clockDiff(d)).toEqual(Number.POSITIVE_INFINITY); expect(b.clockDiff(e)).toBeCloseTo(0.001666667, 6); datenow.and.returnValue(1000 + 10000000*1000); expect(b.clockDiff(c)).toEqual(Number.POSITIVE_INFINITY); expect(b.clockDiff(d)).toEqual(Number.POSITIVE_INFINITY); expect(b.clockDiff(e)).toBeCloseTo(0.001666667, 6); c.tickRate = 1000; expect(b.clockDiff(c)).toEqual(0); c.speed = 1.01; expect(b.clockDiff(c)).toEqual(Number.POSITIVE_INFINITY); }); });