[Time Conductor] Adding tests and fixing failing ones. #933

This commit is contained in:
Andrew Henry 2016-08-24 15:28:19 +01:00 committed by Henry
parent 4cf6126d35
commit c6eaa3d528
22 changed files with 1339 additions and 135 deletions

View File

@ -57,7 +57,7 @@ define([
* @private
*/
function getScaledFormat (d) {
var m = moment.utc(d);
var momentified = moment.utc(d);
/**
* Uses logic from d3 Time-Scales, v3 of the API. See
* https://github.com/d3/d3-3.x-api-reference/blob/master/Time-Scales.md
@ -71,17 +71,17 @@ define([
["HH", function(m) { return m.hours(); }],
["ddd DD", function(m) {
return m.days() &&
m.date() != 1;
m.date() !== 1;
}],
["MMM DD", function(m) { return m.date() != 1; }],
["MMM DD", function(m) { return m.date() !== 1; }],
["MMMM", function(m) {
return m.month();
}],
["YYYY", function() { return true; }]
].filter(function (row){
return row[1](m);
return row[1](momentified);
})[0][0];
};
}
/**
*

View File

@ -0,0 +1,62 @@
/*****************************************************************************
* Open MCT Web, Copyright (c) 2014-2015, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT Web is 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.
*
* Open MCT Web includes source code licensed under additional open source
* licenses. See the Open Source Licenses file (LICENSES.md) included with
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
define([
"./UTCTimeFormat",
"moment"
], function (
UTCTimeFormat,
moment
) {
describe("The UTCTimeFormat class", function () {
var format;
var scale;
beforeEach(function () {
format = new UTCTimeFormat();
scale = {min: 0, max: 0};
});
it("Provides an appropriately scaled time format based on the input" +
" time", function () {
var TWO_HUNDRED_MS = 200;
var THREE_SECONDS = 3000;
var FIVE_MINUTES = 5 * 60 * 1000;
var ONE_HOUR_TWENTY_MINS = (1 * 60 * 60 * 1000) + (20 * 60 * 1000);
var TEN_HOURS = (10 * 60 * 60 * 1000);
var JUNE_THIRD = moment.utc("2016-06-03", "YYYY-MM-DD");
var APRIL = moment.utc("2016-04", "YYYY-MM");
var TWENTY_SIXTEEN = moment.utc("2016", "YYYY");
expect(format.format(TWO_HUNDRED_MS, scale)).toBe(".200");
expect(format.format(THREE_SECONDS, scale)).toBe(":03");
expect(format.format(FIVE_MINUTES, scale)).toBe("00:05");
expect(format.format(ONE_HOUR_TWENTY_MINS, scale)).toBe("01:20");
expect(format.format(TEN_HOURS, scale)).toBe("10");
expect(format.format(JUNE_THIRD, scale)).toBe("Fri 03");
expect(format.format(APRIL, scale)).toBe("April");
expect(format.format(TWENTY_SIXTEEN, scale)).toBe("2016");
});
});
});

View File

@ -78,7 +78,7 @@ define(
this.conductor.on("bounds", this.boundsListener);
this.conductor.on("timeSystem", this.timeSystemListener);
this.conductor.on("follow", this.followListener)
this.conductor.on("follow", this.followListener);
}
};

View File

@ -66,7 +66,7 @@ define([
ConductorService.prototype.getConductor = function () {
return this.tc;
}
};
return ConductorService;
});

View File

@ -79,7 +79,7 @@ define(
return function() {
unsubscribeFunc();
conductor.off('bounds', amendRequests);
}
};
};
return ConductorTelemetryDecorator;

View File

@ -64,6 +64,7 @@ define([
"implementation": TimeConductorController,
"depends": [
"$scope",
"$window",
"timeConductor",
"timeConductorViewService",
"timeSystems[]"

View File

@ -50,21 +50,21 @@ define(['./TimeConductor'], function (TimeConductor) {
it("Allows setting of valid bounds", function () {
bounds = {start: 0, end: 1};
expect(tc.bounds()).not.toBe(bounds);
expect(tc.bounds()).not.toEqual(bounds);
expect(tc.bounds.bind(tc, bounds)).not.toThrow();
expect(tc.bounds()).toBe(bounds);
expect(tc.bounds()).toEqual(bounds);
});
it("Disallows setting of invalid bounds", function () {
bounds = {start: 1, end: 0};
expect(tc.bounds()).not.toBe(bounds);
expect(tc.bounds()).not.toEqual(bounds);
expect(tc.bounds.bind(tc, bounds)).toThrow();
expect(tc.bounds()).not.toBe(bounds);
expect(tc.bounds()).not.toEqual(bounds);
bounds = {start: 1};
expect(tc.bounds()).not.toBe(bounds);
expect(tc.bounds()).not.toEqual(bounds);
expect(tc.bounds.bind(tc, bounds)).toThrow();
expect(tc.bounds()).not.toBe(bounds);
expect(tc.bounds()).not.toEqual(bounds);
});
it("Allows setting of time system with bounds", function () {

View File

@ -0,0 +1,50 @@
/*****************************************************************************
* Open MCT Web, Copyright (c) 2014-2015, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT Web is 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.
*
* Open MCT Web includes source code licensed under additional open source
* licenses. See the Open Source Licenses file (LICENSES.md) included with
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
define(["./LocalClock"], function (LocalClock) {
describe("The LocalClock class", function () {
var clock,
mockTimeout,
timeoutHandle = {};
beforeEach(function () {
mockTimeout = jasmine.createSpy("timeout");
mockTimeout.andReturn(timeoutHandle);
mockTimeout.cancel = jasmine.createSpy("cancel");
clock = new LocalClock(mockTimeout, 0);
clock.start();
});
it("calls listeners on tick with current time", function () {
var mockListener = jasmine.createSpy("listener");
clock.listen(mockListener);
clock.tick();
expect(mockListener).toHaveBeenCalledWith(jasmine.any(Number));
});
it("stops ticking when stop is called", function () {
clock.stop();
expect(mockTimeout.cancel).toHaveBeenCalledWith(timeoutHandle);
});
});
});

View File

@ -22,10 +22,10 @@
define(
[
"zepto",
"d3"
],
function ($, d3) {
function (d3) {
var PADDING = 1;
/**
* The mct-conductor-axis renders a horizontal axis with regular
@ -33,88 +33,102 @@ define(
* be specified as attributes.
*/
function MCTConductorAxis(conductor, formatService) {
function link(scope, element, attrs, ngModelController) {
var target = element[0].firstChild,
height = target.offsetHeight,
padding = 1;
// Dependencies
this.d3 = d3;
this.conductor = conductor;
this.formatService = formatService;
var vis = d3.select(target)
.append('svg:svg')
.attr('width', '100%')
.attr('height', height);
var xAxis = d3.axisTop();
var xScale = d3.scaleUtc();
// Runtime properties (set by 'link' function)
this.target = undefined;
this.xScale = undefined;
this.xAxis = undefined;
this.axisElement = undefined;
this.setScale = this.setScale.bind(this);
this.changeTimeSystem = this.changeTimeSystem.bind(this);
// draw x axis with labels and move to the bottom of the chart area
var axisElement = vis.append("g")
.attr("transform", "translate(0," + (height - padding) + ")");
function setScale() {
var width = target.offsetWidth;
var timeSystem = conductor.timeSystem();
var bounds = conductor.bounds();
if (timeSystem.isUTCBased()) {
xScale.domain([new Date(bounds.start), new Date(bounds.end)]);
} else {
xScale.domain([bounds.start, bounds.end]);
}
xScale.range([padding, width - padding * 2]);
axisElement.call(xAxis);
}
function changeTimeSystem(timeSystem) {
var key = timeSystem.formats()[0];
if (key !== undefined) {
var format = formatService.getFormat(key);
var b = conductor.bounds();
if (timeSystem.isUTCBased()) {
xScale = d3.scaleUtc();
} else {
xScale = d3.scaleLinear();
}
xAxis.scale(xScale);
//Define a custom format function
xAxis.tickFormat(function (tickValue) {
// Normalize date representations to numbers
if (tickValue instanceof Date){
tickValue = tickValue.getTime();
}
return format.format(tickValue, {
min: b.start,
max: b.end
});
});
axisElement.call(xAxis);
}
}
scope.resize = setScale;
conductor.on('timeSystem', changeTimeSystem);
//On conductor bounds changes, redraw ticks
conductor.on('bounds', function (bounds) {
setScale();
});
if (conductor.timeSystem() !== undefined) {
changeTimeSystem(conductor.timeSystem());
setScale();
}
}
return {
restrict: "E",
template: "<div class=\"l-axis-holder\" mct-resize=\"resize()\"></div>",
priority: 1000,
link: link
};
// Angular Directive interface
this.link = this.link.bind(this);
this.restrict = "E";
this.template =
"<div class=\"l-axis-holder\" mct-resize=\"resize()\"></div>";
this.priority = 1000;
}
return MCTConductorAxis;
MCTConductorAxis.prototype.setScale = function () {
var width = this.target.offsetWidth;
var timeSystem = this.conductor.timeSystem();
var bounds = this.conductor.bounds();
if (timeSystem.isUTCBased()) {
this.xScale = this.xScale || this.d3.scaleUtc();
this.xScale.domain([new Date(bounds.start), new Date(bounds.end)]);
} else {
this.xScale = this.xScale || this.d3.scaleLinear();
this.xScale.domain([bounds.start, bounds.end]);
}
this.xScale.range([PADDING, width - PADDING * 2]);
this.axisElement.call(this.xAxis);
};
MCTConductorAxis.prototype.changeTimeSystem = function (timeSystem) {
var key = timeSystem.formats()[0];
if (key !== undefined) {
var format = this.formatService.getFormat(key);
var bounds = this.conductor.bounds();
if (timeSystem.isUTCBased()) {
this.xScale = this.d3.scaleUtc();
} else {
this.xScale = this.d3.scaleLinear();
}
this.xAxis.scale(this.xScale);
//Define a custom format function
this.xAxis.tickFormat(function (tickValue) {
// Normalize date representations to numbers
if (tickValue instanceof Date){
tickValue = tickValue.getTime();
}
return format.format(tickValue, {
min: bounds.start,
max: bounds.end
});
});
this.axisElement.call(this.xAxis);
}
};
MCTConductorAxis.prototype.link = function (scope, element) {
var conductor = this.conductor;
this.target = element[0].firstChild;
var height = this.target.offsetHeight;
var vis = this.d3.select(this.target)
.append('svg:svg')
.attr('width', '100%')
.attr('height', height);
this.xAxis = this.d3.axisTop();
// draw x axis with labels and move to the bottom of the chart area
this.axisElement = vis.append("g")
.attr("transform", "translate(0," + (height - PADDING) + ")");
scope.resize = this.setScale;
conductor.on('timeSystem', this.changeTimeSystem);
//On conductor bounds changes, redraw ticks
conductor.on('bounds', this.setScale);
if (conductor.timeSystem() !== undefined) {
this.changeTimeSystem(conductor.timeSystem());
this.setScale();
}
};
return function(conductor, formatService) {
return new MCTConductorAxis(conductor, formatService);
};
}
);

View File

@ -0,0 +1,136 @@
/*****************************************************************************
* Open MCT Web, Copyright (c) 2014-2015, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT Web is 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.
*
* Open MCT Web includes source code licensed under additional open source
* licenses. See the Open Source Licenses file (LICENSES.md) included with
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
define(['./MctConductorAxis'], function (MctConductorAxis) {
describe("The MctConductorAxis directive", function () {
var directive,
mockConductor,
mockFormatService,
mockScope,
mockElement,
mockTarget,
mockBounds,
d3;
beforeEach(function () {
mockScope = {};
//Add some HTML elements
mockTarget = {
offsetWidth: 0,
offsetHeight: 0
};
mockElement = {
firstChild: mockTarget
};
mockBounds = {
start: 100,
end: 200
};
mockConductor = jasmine.createSpyObj("conductor", [
"timeSystem",
"bounds",
"on"
]);
mockConductor.bounds.andReturn(mockBounds);
mockFormatService = jasmine.createSpyObj("formatService", [
"getFormat"
]);
var d3Functions = [
"scale",
"scaleUtc",
"scaleLinear",
"select",
"append",
"attr",
"axisTop",
"call",
"tickFormat",
"domain",
"range"
];
d3 = jasmine.createSpyObj("d3", d3Functions);
d3Functions.forEach(function(func) {
d3[func].andReturn(d3);
});
directive = new MctConductorAxis(mockConductor, mockFormatService);
directive.d3 = d3;
directive.link(mockScope, [mockElement]);
});
it("listens for changes to time system and bounds", function () {
expect(mockConductor.on).toHaveBeenCalledWith("timeSystem", directive.changeTimeSystem);
expect(mockConductor.on).toHaveBeenCalledWith("bounds", directive.setScale);
});
describe("when the time system changes", function () {
var mockTimeSystem;
var mockFormat;
beforeEach(function() {
mockTimeSystem = jasmine.createSpyObj("timeSystem", [
"formats",
"isUTCBased"
]);
mockFormat = jasmine.createSpyObj("format", [
"format"
]);
mockTimeSystem.formats.andReturn(["mockFormat"]);
mockFormatService.getFormat.andReturn(mockFormat);
});
it("uses a UTC scale for UTC time systems", function () {
mockTimeSystem.isUTCBased.andReturn(true);
directive.changeTimeSystem(mockTimeSystem);
expect(d3.scaleUtc).toHaveBeenCalled();
expect(d3.scaleLinear).not.toHaveBeenCalled();
});
it("uses a linear scale for non-UTC time systems", function () {
mockTimeSystem.isUTCBased.andReturn(false);
directive.changeTimeSystem(mockTimeSystem);
expect(d3.scaleLinear).toHaveBeenCalled();
expect(d3.scaleUtc).not.toHaveBeenCalled();
});
it("sets axis domain to time conductor bounds", function () {
mockTimeSystem.isUTCBased.andReturn(false);
mockConductor.timeSystem.andReturn(mockTimeSystem);
directive.setScale();
expect(d3.domain).toHaveBeenCalledWith([mockBounds.start, mockBounds.end]);
});
it("uses the format specified by the time system to format tick" +
" labels", function () {
directive.changeTimeSystem(mockTimeSystem);
expect(d3.tickFormat).toHaveBeenCalled();
d3.tickFormat.mostRecentCall.args[0]();
expect(mockFormat.format).toHaveBeenCalled();
});
});
});
});

View File

@ -0,0 +1,49 @@
/*****************************************************************************
* Open MCT Web, Copyright (c) 2014-2015, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT Web is 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.
*
* Open MCT Web includes source code licensed under additional open source
* licenses. See the Open Source Licenses file (LICENSES.md) included with
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
define(['./NumberFormat'], function (NumberFormat) {
describe("The NumberFormat class", function () {
var format;
beforeEach(function () {
format = new NumberFormat();
});
it("The format function takes a string and produces a number", function () {
var text = format.format(1);
expect(text).toBe("1");
expect(typeof(text)).toBe("string");
});
it("The parse function takes a string and produces a number", function () {
var number = format.parse("1");
expect(number).toBe(1);
expect(typeof(number)).toBe("number");
});
it("validates that the input is a number", function () {
expect(format.validate("1")).toBe(true);
expect(format.validate(1)).toBe(true);
expect(format.validate("1.1")).toBe(true);
expect(format.validate("abc")).toBe(false);
});
});
});

View File

@ -26,7 +26,7 @@ define(
],
function (TimeConductorValidation) {
function TimeConductorController($scope, timeConductor, conductorViewService, timeSystems) {
function TimeConductorController($scope, $window, timeConductor, conductorViewService, timeSystems) {
var self = this;
@ -38,6 +38,7 @@ define(
});
this.$scope = $scope;
this.$window = $window;
this.conductorViewService = conductorViewService;
this.conductor = timeConductor;
this.modes = conductorViewService.availableModes();
@ -99,7 +100,6 @@ define(
// Watch scope for selection of mode or time system by user
this.$scope.$watch('modeModel.selectedKey', this.setMode);
this.$scope.$watch('timeSystem', this.changeTimeSystem);
};
/**
@ -113,7 +113,7 @@ define(
this.$scope.boundsModel.end = bounds.end;
if (!this.pendingUpdate) {
this.pendingUpdate = true;
requestAnimationFrame(function () {
this.$window.requestAnimationFrame(function () {
this.pendingUpdate = false;
this.$scope.$digest();
}.bind(this));
@ -136,16 +136,8 @@ define(
* @private
*/
TimeConductorController.prototype.setFormFromDeltas = function (deltas) {
/*
* If the selected mode defines deltas, set them in the form
*/
if (deltas !== undefined) {
this.$scope.boundsModel.startDelta = deltas.start;
this.$scope.boundsModel.endDelta = deltas.end;
} else {
this.$scope.boundsModel.startDelta = 0;
this.$scope.boundsModel.endDelta = 0;
}
this.$scope.boundsModel.startDelta = deltas.start;
this.$scope.boundsModel.endDelta = deltas.end;
};
/**
@ -180,7 +172,7 @@ define(
var deltas = {
start: boundsFormModel.startDelta,
end: boundsFormModel.endDelta
}
};
if (this.validation.validateStartDelta(deltas.start) && this.validation.validateEndDelta(deltas.end)) {
//Sychronize deltas between form and mode
this.conductorViewService.deltas(deltas);
@ -204,6 +196,8 @@ define(
};
/**
* Respond to time system selection from UI
*
* Allows time system to be changed by key. This supports selection
* from the menu. Resolves a TimeSystem object and then invokes
* TimeConductorController#setTimeSystem
@ -211,13 +205,15 @@ define(
* @see TimeConductorController#setTimeSystem
*/
TimeConductorController.prototype.selectTimeSystemByKey = function(key){
var selected = this.timeSystems.find(function (timeSystem){
var selected = this.timeSystems.filter(function (timeSystem){
return timeSystem.metadata.key === key;
});
})[0];
this.conductor.timeSystem(selected, selected.defaults().bounds);
};
/**
* Handles time system change from time conductor
*
* Sets the selected time system. Will populate form with the default
* bounds and deltas defined in the selected time system.
*
@ -226,7 +222,13 @@ define(
*/
TimeConductorController.prototype.changeTimeSystem = function (newTimeSystem) {
if (newTimeSystem && (newTimeSystem !== this.$scope.timeSystemModel.selected)) {
this.setFormFromDeltas((newTimeSystem.defaults() || {}).deltas);
if (newTimeSystem.defaults()){
var deltas = newTimeSystem.defaults().deltas || {start: 0, end: 0};
var bounds = newTimeSystem.defaults().bounds || {start: 0, end: 0};
this.setFormFromDeltas(deltas);
this.setFormFromBounds(bounds);
}
this.setFormFromTimeSystem(newTimeSystem);
}
};

View File

@ -0,0 +1,335 @@
/*****************************************************************************
* Open MCT Web, Copyright (c) 2014-2015, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT Web is 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.
*
* Open MCT Web includes source code licensed under additional open source
* licenses. See the Open Source Licenses file (LICENSES.md) included with
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
define(['./TimeConductorController'], function (TimeConductorController) {
describe("The time conductor controller", function () {
var mockScope;
var mockWindow;
var mockTimeConductor;
var mockConductorViewService;
var mockTimeSystems;
var controller;
beforeEach(function () {
mockScope = jasmine.createSpyObj("$scope", ["$watch"]);
mockWindow = jasmine.createSpyObj("$window", ["requestAnimationFrame"]);
mockTimeConductor = jasmine.createSpyObj(
"TimeConductor",
[
"bounds",
"timeSystem",
"on"
]
);
mockTimeConductor.bounds.andReturn({start: undefined, end: undefined});
mockConductorViewService = jasmine.createSpyObj(
"ConductorViewService",
[
"availableModes",
"mode",
"availableTimeSystems",
"deltas"
]
);
mockConductorViewService.availableModes.andReturn([]);
mockConductorViewService.availableTimeSystems.andReturn([]);
mockTimeSystems = [];
});
function getListener(name) {
return mockTimeConductor.on.calls.filter(function (call){
return call.args[0] === name;
})[0].args[1];
}
describe("", function (){
beforeEach(function() {
controller = new TimeConductorController(
mockScope,
mockWindow,
mockTimeConductor,
mockConductorViewService,
mockTimeSystems
);
});
});
describe("when time conductor state changes", function () {
var mockFormat;
var mockDeltaFormat;
var defaultBounds;
var defaultDeltas;
var mockDefaults;
var timeSystem;
var tsListener;
beforeEach(function () {
mockFormat = {};
mockDeltaFormat = {};
defaultBounds = {
start: 2,
end: 3
};
defaultDeltas = {
start: 10,
end: 20
};
mockDefaults = {
deltas: defaultDeltas,
bounds: defaultBounds
};
timeSystem = {
formats: function () {
return [mockFormat];
},
deltaFormat: function () {
return mockDeltaFormat;
},
defaults: function () {
return mockDefaults;
}
};
controller = new TimeConductorController(
mockScope,
mockWindow,
mockTimeConductor,
mockConductorViewService,
mockTimeSystems
);
tsListener = getListener("timeSystem");
});
it("listens for changes to conductor state", function () {
expect(mockTimeConductor.on).toHaveBeenCalledWith("timeSystem", jasmine.any(Function));
expect(mockTimeConductor.on).toHaveBeenCalledWith("bounds", jasmine.any(Function));
expect(mockTimeConductor.on).toHaveBeenCalledWith("follow", jasmine.any(Function));
});
it("when time system changes, sets time system on scope", function () {
expect(tsListener).toBeDefined();
tsListener(timeSystem);
expect(mockScope.timeSystemModel).toBeDefined();
expect(mockScope.timeSystemModel.selected).toBe(timeSystem);
expect(mockScope.timeSystemModel.format).toBe(mockFormat);
expect(mockScope.timeSystemModel.deltaFormat).toBe(mockDeltaFormat);
});
it("when time system changes, sets defaults on scope", function () {
expect(tsListener).toBeDefined();
tsListener(timeSystem);
expect(mockScope.boundsModel.start).toEqual(defaultBounds.start);
expect(mockScope.boundsModel.end).toEqual(defaultBounds.end);
expect(mockScope.boundsModel.startDelta).toEqual(defaultDeltas.start);
expect(mockScope.boundsModel.endDelta).toEqual(defaultDeltas.end);
});
it("when bounds change, sets them on scope", function () {
var bounds = {
start: 1,
end: 2
};
var boundsListener = getListener("bounds");
expect(boundsListener).toBeDefined();
boundsListener(bounds);
expect(mockScope.boundsModel).toBeDefined();
expect(mockScope.boundsModel.start).toEqual(bounds.start);
expect(mockScope.boundsModel.end).toEqual(bounds.end);
});
it("responds to a change in 'follow' state of the time conductor", function () {
var followListener = getListener("follow");
expect(followListener).toBeDefined();
followListener(true);
expect(mockScope.followMode).toEqual(true);
followListener(false);
expect(mockScope.followMode).toEqual(false);
});
});
describe("when user makes changes from UI", function () {
var mode = "realtime";
var ts1Metadata;
var ts2Metadata;
var ts3Metadata;
var mockTimeSystemConstructors;
beforeEach(function () {
mode = "realtime";
ts1Metadata = {
'key': 'ts1',
'name': 'Time System One',
'cssClass': 'cssClassOne'
};
ts2Metadata = {
'key': 'ts2',
'name': 'Time System Two',
'cssClass': 'cssClassTwo'
};
ts3Metadata = {
'key': 'ts3',
'name': 'Time System Three',
'cssClass': 'cssClassThree'
};
mockTimeSystems = [
{
metadata: ts1Metadata
},
{
metadata: ts2Metadata
},
{
metadata: ts3Metadata
}
];
//Wrap in mock constructors
mockTimeSystemConstructors = mockTimeSystems.map(function (mockTimeSystem) {
return function () {
return mockTimeSystem;
};
});
});
it("sets the mode on scope", function () {
controller = new TimeConductorController(
mockScope,
mockWindow,
mockTimeConductor,
mockConductorViewService,
mockTimeSystemConstructors
);
mockConductorViewService.availableTimeSystems.andReturn(mockTimeSystems);
controller.setMode(mode);
expect(mockScope.modeModel.selectedKey).toEqual(mode);
});
it("sets available time systems on scope when mode changes", function () {
controller = new TimeConductorController(
mockScope,
mockWindow,
mockTimeConductor,
mockConductorViewService,
mockTimeSystemConstructors
);
mockConductorViewService.availableTimeSystems.andReturn(mockTimeSystems);
controller.setMode(mode);
expect(mockScope.timeSystemModel.options.length).toEqual(3);
expect(mockScope.timeSystemModel.options[0]).toEqual(ts1Metadata);
expect(mockScope.timeSystemModel.options[1]).toEqual(ts2Metadata);
expect(mockScope.timeSystemModel.options[2]).toEqual(ts3Metadata);
});
it("sets bounds on the time conductor", function () {
var formModel = {
start: 1,
end: 10
};
controller = new TimeConductorController(
mockScope,
mockWindow,
mockTimeConductor,
mockConductorViewService,
mockTimeSystemConstructors
);
controller.updateBoundsFromForm(formModel);
expect(mockTimeConductor.bounds).toHaveBeenCalledWith(formModel);
});
it("applies deltas when they change in form", function () {
var deltas = {
start: 1000,
end: 2000
};
var formModel = {
startDelta: deltas.start,
endDelta: deltas.end
};
controller = new TimeConductorController(
mockScope,
mockWindow,
mockTimeConductor,
mockConductorViewService,
mockTimeSystemConstructors
);
controller.updateDeltasFromForm(formModel);
expect(mockConductorViewService.deltas).toHaveBeenCalledWith(deltas);
});
it("sets the time system on the time conductor", function () {
var defaultBounds = {
start: 5,
end: 6
};
var timeSystem = {
metadata: {
key: 'testTimeSystem'
},
defaults: function() {
return {
bounds: defaultBounds
};
}
};
mockTimeSystems = [
// Wrap as constructor function
function() {
return timeSystem;
}
];
controller = new TimeConductorController(
mockScope,
mockWindow,
mockTimeConductor,
mockConductorViewService,
mockTimeSystems
);
controller.selectTimeSystemByKey('testTimeSystem');
expect(mockTimeConductor.timeSystem).toHaveBeenCalledWith(timeSystem, defaultBounds);
});
});
});
});

View File

@ -39,8 +39,8 @@ define(
this._tickSourceUnlisten = undefined;
this._timeSystems = timeSystems;
this._availableTickSources = undefined;
this.changeTimeSystem = this.changeTimeSystem.bind(this);
this.tick = this.tick.bind(this);
//Set the time system initially
if (conductor.timeSystem()) {
@ -81,6 +81,7 @@ define(
end: 0
}
};
this.conductor.bounds(defaults.bounds);
this.deltas(defaults.deltas);
@ -130,7 +131,7 @@ define(
}
this._tickSource = tickSource;
if (tickSource) {
this._tickSourceUnlisten = tickSource.listen(this.tick.bind(this));
this._tickSourceUnlisten = tickSource.listen(this.tick);
//Now following a tick source
this.conductor.follow(true);
} else {

View File

@ -0,0 +1,210 @@
/*****************************************************************************
* Open MCT Web, Copyright (c) 2014-2015, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT Web is 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.
*
* Open MCT Web includes source code licensed under additional open source
* licenses. See the Open Source Licenses file (LICENSES.md) included with
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
define(['./TimeConductorMode'], function (TimeConductorMode) {
describe("The Time Conductor Mode", function () {
var mockTimeConductor,
fixedModeMetaData,
mockTimeSystems,
fixedTimeSystem,
realtimeModeMetaData,
realtimeTimeSystem,
mockTickSource,
mockBounds,
mode;
beforeEach(function () {
fixedModeMetaData = {
key: "fixed"
};
realtimeModeMetaData = {
key: "realtime"
};
mockBounds = {
start: 0,
end: 1
};
fixedTimeSystem = jasmine.createSpyObj("timeSystem", [
"defaults",
"tickSources"
]);
fixedTimeSystem.tickSources.andReturn([]);
mockTickSource = jasmine.createSpyObj("tickSource", [
"listen"
]);
mockTickSource.metadata = {
mode: "realtime"
};
realtimeTimeSystem = jasmine.createSpyObj("realtimeTimeSystem", [
"defaults",
"tickSources"
]);
realtimeTimeSystem.tickSources.andReturn([mockTickSource]);
//Do not return any time systems initially for a default
// construction configuration that works without any additional work
mockTimeSystems = [];
mockTimeConductor = jasmine.createSpyObj("timeConductor", [
"bounds",
"timeSystem",
"on",
"off",
"follow"
]);
mockTimeConductor.bounds.andReturn(mockBounds);
});
it("Reacts to changes in conductor time system", function () {
mode = new TimeConductorMode(fixedModeMetaData, mockTimeConductor, mockTimeSystems);
expect(mockTimeConductor.on).toHaveBeenCalledWith("timeSystem", mode.changeTimeSystem);
});
it("Stops listening to time system changes on destroy", function () {
mode = new TimeConductorMode(fixedModeMetaData, mockTimeConductor, mockTimeSystems);
mode.destroy();
expect(mockTimeConductor.off).toHaveBeenCalledWith("timeSystem", mode.changeTimeSystem);
});
it("Filters available time systems to those with tick sources that" +
" support this mode", function () {
mockTimeSystems = [fixedTimeSystem, realtimeTimeSystem];
mode = new TimeConductorMode(realtimeModeMetaData, mockTimeConductor, mockTimeSystems);
var availableTimeSystems = mode.availableTimeSystems();
expect(availableTimeSystems.length).toBe(1);
expect(availableTimeSystems.indexOf(fixedTimeSystem)).toBe(-1);
expect(availableTimeSystems.indexOf(realtimeTimeSystem)).toBe(0);
});
describe("Changing the time system", function () {
var defaults;
beforeEach(function () {
defaults = {
bounds: {
start: 1,
end: 2
},
deltas: {
start: 3,
end: 4
}
};
fixedTimeSystem.defaults.andReturn(defaults);
});
it ("sets defaults from new time system", function() {
mode = new TimeConductorMode(fixedModeMetaData, mockTimeConductor, mockTimeSystems);
spyOn(mode, "deltas");
mode.deltas.andCallThrough();
mode.changeTimeSystem(fixedTimeSystem);
expect(mockTimeConductor.bounds).toHaveBeenCalledWith(defaults.bounds);
expect(mode.deltas).toHaveBeenCalledWith(defaults.deltas);
});
it ("If a tick source is available, sets the tick source", function() {
mode = new TimeConductorMode(realtimeModeMetaData, mockTimeConductor, mockTimeSystems);
mode.changeTimeSystem(realtimeTimeSystem);
var currentTickSource = mode.tickSource();
expect(currentTickSource).toBe(mockTickSource);
});
});
describe("Setting a tick source", function () {
var mockUnlistener;
beforeEach(function() {
mockUnlistener = jasmine.createSpy("unlistener");
mockTickSource.listen.andReturn(mockUnlistener);
mode = new TimeConductorMode(realtimeModeMetaData, mockTimeConductor, mockTimeSystems);
mode.tickSource(mockTickSource);
});
it ("Unlistens from old tick source", function() {
mode.tickSource(mockTickSource);
expect(mockUnlistener).toHaveBeenCalled();
});
it ("Listens to new tick source", function() {
expect(mockTickSource.listen).toHaveBeenCalledWith(mode.tick);
});
it ("Sets 'follow' state on time conductor", function() {
expect(mockTimeConductor.follow).toHaveBeenCalledWith(true);
});
it ("on destroy, unlistens from tick source", function() {
mode.destroy();
expect(mockUnlistener).toHaveBeenCalled();
});
});
describe("setting deltas", function () {
beforeEach(function() {
mode = new TimeConductorMode(realtimeModeMetaData, mockTimeConductor, mockTimeSystems);
});
it ("sets the bounds on the time conductor based on new delta" +
" values", function() {
var deltas = {
start: 20,
end: 10
};
mode.deltas(deltas);
expect(mockTimeConductor.bounds).toHaveBeenCalledWith({
start: mockBounds.end - deltas.start,
end: mockBounds.end + deltas.end
});
});
});
describe("ticking", function () {
beforeEach(function() {
mode = new TimeConductorMode(realtimeModeMetaData, mockTimeConductor, mockTimeSystems);
});
it ("sets bounds based on current delta values", function() {
var deltas = {
start: 20,
end: 10
};
var time = 100;
mode.deltas(deltas);
mode.tick(time);
expect(mockTimeConductor.bounds).toHaveBeenCalledWith({
start: time - deltas.start,
end:time + deltas.end
});
});
});
});
});

View File

@ -31,7 +31,7 @@ define(
*/
function TimeConductorValidation(conductor) {
var self = this;
this.conductor = conductor
this.conductor = conductor;
/*
* Bind all class functions to 'this'

View File

@ -0,0 +1,73 @@
/*****************************************************************************
* Open MCT Web, Copyright (c) 2014-2015, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT Web is 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.
*
* Open MCT Web includes source code licensed under additional open source
* licenses. See the Open Source Licenses file (LICENSES.md) included with
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
define(['./TimeConductorValidation'], function (TimeConductorValidation) {
describe("The Time Conductor Validation class", function () {
var timeConductorValidation,
mockTimeConductor;
beforeEach(function () {
mockTimeConductor = jasmine.createSpyObj("timeConductor", [
"validateBounds",
"bounds"
]);
timeConductorValidation = new TimeConductorValidation(mockTimeConductor);
});
describe("Validates start and end values using Time Conductor", function () {
beforeEach(function() {
var mockBounds = {
start: 10,
end: 20
};
mockTimeConductor.bounds.andReturn(mockBounds);
});
it("Validates start values using Time Conductor", function () {
var startValue = 30;
timeConductorValidation.validateStart(startValue);
expect(mockTimeConductor.validateBounds).toHaveBeenCalled();
});
it("Validates end values using Time Conductor", function () {
var endValue = 40;
timeConductorValidation.validateEnd(endValue);
expect(mockTimeConductor.validateBounds).toHaveBeenCalled();
});
});
it("Validates that start delta is valid number > 0", function () {
expect(timeConductorValidation.validateStartDelta(-1)).toBe(false);
expect(timeConductorValidation.validateStartDelta("abc")).toBe(false);
expect(timeConductorValidation.validateStartDelta("1")).toBe(true);
expect(timeConductorValidation.validateStartDelta(1)).toBe(true);
});
it("Validates that end delta is valid number >= 0", function () {
expect(timeConductorValidation.validateEndDelta(-1)).toBe(false);
expect(timeConductorValidation.validateEndDelta("abc")).toBe(false);
expect(timeConductorValidation.validateEndDelta("1")).toBe(true);
expect(timeConductorValidation.validateEndDelta(0)).toBe(true);
expect(timeConductorValidation.validateEndDelta(1)).toBe(true);
});
});
});

View File

@ -36,7 +36,7 @@ define(
* @constructor
*/
function TimeConductorViewService(conductor, timeSystems) {
this._timeSystems = timeSystems = timeSystems.map(
this._timeSystems = timeSystems.map(
function (timeSystemConstructor) {
return timeSystemConstructor();
});
@ -63,34 +63,38 @@ define(
}
};
function timeSystemsForMode(sourceType) {
return timeSystems.filter(function (timeSystem){
return timeSystem.tickSources().some(function (tickSource){
return tickSource.metadata.mode === sourceType;
});
function hasTickSource(sourceType, timeSystem) {
return timeSystem.tickSources().some(function (tickSource){
return tickSource.metadata.mode === sourceType;
});
}
var timeSystemsForMode = function (sourceType) {
return this._timeSystems.filter(hasTickSource.bind(this, sourceType));
}.bind(this);
//Only show 'real-time mode' if appropriate time systems available
if (timeSystemsForMode('realtime').length > 0 ) {
this._availableModes['realtime'] = {
var realtimeMode = {
key: 'realtime',
cssclass: 'icon-clock',
label: 'Real-time',
name: 'Real-time Mode',
description: 'Monitor real-time streaming data as it comes in. The Time Conductor and displays will automatically advance themselves based on a UTC clock.'
};
this._availableModes[realtimeMode.key] = realtimeMode;
}
//Only show 'LAD mode' if appropriate time systems available
if (timeSystemsForMode('LAD').length > 0) {
this._availableModes['latest'] = {
var ladMode = {
key: 'LAD',
cssclass: 'icon-database',
label: 'LAD',
name: 'LAD Mode',
description: 'Latest Available Data mode monitors real-time streaming data as it comes in. The Time Conductor and displays will only advance when data becomes available.'
};
this._availableModes[ladMode.key] = ladMode;
}
}
@ -114,6 +118,12 @@ define(
*
*/
TimeConductorViewService.prototype.mode = function (newModeKey) {
function contains(timeSystems, ts) {
return timeSystems.filter(function (t) {
return t.metadata.key === ts.metadata.key;
}).length > 0;
}
if (arguments.length === 1) {
var timeSystem = this._conductor.timeSystem();
var modes = this.availableModes();
@ -122,13 +132,10 @@ define(
if (this._mode) {
this._mode.destroy();
}
function contains(timeSystems, timeSystem) {
return timeSystems.find(function (t) {
return t.metadata.key === timeSystem.metadata.key;
}) !== undefined;
}
this._mode = new TimeConductorMode(modeMetaData, this._conductor, this._timeSystems);
// If no time system set on time conductor, or the currently selected time system is not available in
// the new mode, default to first available time system
if (!timeSystem || !contains(this._mode.availableTimeSystems(), timeSystem)) {
timeSystem = this._mode.availableTimeSystems()[0];
this._conductor.timeSystem(timeSystem, timeSystem.defaults().bounds);
@ -169,7 +176,7 @@ define(
*/
TimeConductorViewService.prototype.deltas = function () {
//Deltas stored on mode. Use .apply to preserve arguments
return this._mode.deltas.apply(this._mode, arguments)
return this._mode.deltas.apply(this._mode, arguments);
};
/**

View File

@ -0,0 +1,185 @@
/*****************************************************************************
* Open MCT Web, Copyright (c) 2014-2015, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT Web is 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.
*
* Open MCT Web includes source code licensed under additional open source
* licenses. See the Open Source Licenses file (LICENSES.md) included with
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
define(['./TimeConductorViewService'], function (TimeConductorViewService) {
describe("The Time Conductor view service", function () {
var mockTimeConductor;
var basicTimeSystem;
var tickingTimeSystem;
var viewService;
var tickingTimeSystemDefaults;
function mockConstructor(object) {
return function () {
return object;
};
}
beforeEach(function () {
mockTimeConductor = jasmine.createSpyObj("timeConductor", [
"timeSystem",
"bounds",
"follow",
"on",
"off"
]);
basicTimeSystem = jasmine.createSpyObj("basicTimeSystem", [
"tickSources",
"defaults"
]);
basicTimeSystem.metadata = {
key: "basic"
};
basicTimeSystem.tickSources.andReturn([]);
basicTimeSystem.defaults.andReturn({
bounds: {
start: 0,
end: 1
},
deltas: {
start: 0,
end: 0
}
});
//Initialize conductor
mockTimeConductor.timeSystem.andReturn(basicTimeSystem);
mockTimeConductor.bounds.andReturn({start: 0, end: 1});
tickingTimeSystem = jasmine.createSpyObj("tickingTimeSystem", [
"tickSources",
"defaults"
]);
tickingTimeSystem.metadata = {
key: "ticking"
};
tickingTimeSystemDefaults = {
bounds: {
start: 100,
end: 200
},
deltas: {
start: 1000,
end: 500
}
};
tickingTimeSystem.defaults.andReturn(tickingTimeSystemDefaults);
});
it("At a minimum supports fixed mode", function () {
var mockTimeSystems = [mockConstructor(basicTimeSystem)];
viewService = new TimeConductorViewService(mockTimeConductor, mockTimeSystems);
var availableModes = viewService.availableModes();
expect(availableModes.fixed).toBeDefined();
});
it("Supports realtime mode if appropriate tick source(s) availables", function () {
var mockTimeSystems = [mockConstructor(tickingTimeSystem)];
var mockRealtimeTickSource = {
metadata: {
mode: 'realtime'
}
};
tickingTimeSystem.tickSources.andReturn([mockRealtimeTickSource]);
viewService = new TimeConductorViewService(mockTimeConductor, mockTimeSystems);
var availableModes = viewService.availableModes();
expect(availableModes.realtime).toBeDefined();
});
it("Supports LAD mode if appropriate tick source(s) available", function () {
var mockTimeSystems = [mockConstructor(tickingTimeSystem)];
var mockLADTickSource = {
metadata: {
mode: 'LAD'
}
};
tickingTimeSystem.tickSources.andReturn([mockLADTickSource]);
viewService = new TimeConductorViewService(mockTimeConductor, mockTimeSystems);
var availableModes = viewService.availableModes();
expect(availableModes.LAD).toBeDefined();
});
describe("when mode is changed", function () {
it("destroys previous mode", function () {
var mockTimeSystems = [mockConstructor(basicTimeSystem)];
var oldMode = jasmine.createSpyObj("conductorMode", [
"destroy"
]);
viewService = new TimeConductorViewService(mockTimeConductor, mockTimeSystems);
viewService._mode = oldMode;
viewService.mode('fixed');
expect(oldMode.destroy).toHaveBeenCalled();
});
describe("the time system", function () {
it("is retained if available in new mode", function () {
var mockTimeSystems = [mockConstructor(basicTimeSystem), mockConstructor(tickingTimeSystem)];
var mockRealtimeTickSource = {
metadata: {
mode: 'realtime'
},
listen: function() {}
};
tickingTimeSystem.tickSources.andReturn([mockRealtimeTickSource]);
viewService = new TimeConductorViewService(mockTimeConductor, mockTimeSystems);
//Set time system to one known to support realtime mode
mockTimeConductor.timeSystem.andReturn(tickingTimeSystem);
//Select realtime mode
mockTimeConductor.timeSystem.reset();
viewService.mode('realtime');
expect(mockTimeConductor.timeSystem).not.toHaveBeenCalledWith(tickingTimeSystem, tickingTimeSystemDefaults.bounds);
});
it("is defaulted if selected time system not available in new mode", function () {
var mockTimeSystems = [mockConstructor(basicTimeSystem), mockConstructor(tickingTimeSystem)];
var mockRealtimeTickSource = {
metadata: {
mode: 'realtime'
},
listen: function() {}
};
tickingTimeSystem.tickSources.andReturn([mockRealtimeTickSource]);
viewService = new TimeConductorViewService(mockTimeConductor, mockTimeSystems);
//Set time system to one known to not support realtime mode
mockTimeConductor.timeSystem.andReturn(basicTimeSystem);
//Select realtime mode
mockTimeConductor.timeSystem.reset();
viewService.mode('realtime');
expect(mockTimeConductor.timeSystem).toHaveBeenCalledWith(tickingTimeSystem, tickingTimeSystemDefaults.bounds);
});
});
});
});
});

View File

@ -0,0 +1,46 @@
/*****************************************************************************
* Open MCT Web, Copyright (c) 2014-2015, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT Web is 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.
*
* Open MCT Web includes source code licensed under additional open source
* licenses. See the Open Source Licenses file (LICENSES.md) included with
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
define(['./UTCTimeSystem'], function (UTCTimeSystem) {
describe("The UTCTimeSystem class", function () {
var timeSystem,
mockTimeout;
beforeEach(function () {
mockTimeout = jasmine.createSpy("timeout");
timeSystem = new UTCTimeSystem(mockTimeout);
});
it("defines at least one format", function () {
expect(timeSystem.formats().length).toBeGreaterThan(0);
});
it("defines a tick source", function () {
var tickSources = timeSystem.tickSources();
expect(tickSources.length).toBeGreaterThan(0);
});
it("defines some defaults", function () {
expect(timeSystem.defaults()).toBeDefined();
});
});
});

View File

@ -239,7 +239,7 @@ define(
setBasePanZoom(bounds);
requery();
}
self.updateStatus($scope.domainObject, follow);
self.setUnsynchedStatus($scope.domainObject, follow && self.isZoomed());
}
this.modeOptions = new PlotModeOptions([], subPlotFactory);
@ -370,9 +370,9 @@ define(
return this.pending;
};
PlotController.prototype.updateStatus = function (domainObject, follow) {
PlotController.prototype.setUnsynchedStatus = function (domainObject, status) {
if (domainObject.hasCapability('status')) {
domainObject.getCapability('status').set('timeconductor-unsynced', follow && this.isZoomed());
domainObject.getCapability('status').set('timeconductor-unsynced', status);
}
};

View File

@ -35,6 +35,7 @@ define(
mockHandle,
mockDomainObject,
mockSeries,
mockStatusCapability,
controller;
function bind(method, thisObj) {
@ -71,7 +72,7 @@ define(
);
mockDomainObject = jasmine.createSpyObj(
"domainObject",
["getId", "getModel", "getCapability"]
["getId", "getModel", "getCapability", "hasCapability"]
);
mockHandler = jasmine.createSpyObj(
"telemetrySubscriber",
@ -95,6 +96,11 @@ define(
['getPointCount', 'getDomainValue', 'getRangeValue']
);
mockStatusCapability = jasmine.createSpyObj(
"statusCapability",
["set"]
);
mockHandler.handle.andReturn(mockHandle);
mockThrottle.andCallFake(function (fn) {
return fn;
@ -230,6 +236,34 @@ define(
expect(bind(controller.unzoom, controller)).not.toThrow();
});
it("sets status when plot becomes detached from time conductor", function () {
mockScope.$watch.mostRecentCall.args[1](mockDomainObject);
function boundsEvent(){
fireEvent("telemetry:display:bounds", [
{},
{ start: 10, end: 100 },
true
]);
}
mockDomainObject.hasCapability.andCallFake(function (name) {
return name === "status";
});
mockDomainObject.getCapability.andReturn(mockStatusCapability);
spyOn(controller, "isZoomed");
//Mock zoomed in state
controller.isZoomed.andReturn(true);
boundsEvent();
expect(mockStatusCapability.set).toHaveBeenCalledWith("timeconductor-unsynced", true);
//"Reset" zoom
controller.isZoomed.andReturn(false);
boundsEvent();
expect(mockStatusCapability.set).toHaveBeenCalledWith("timeconductor-unsynced", false);
});
it("indicates if a request is pending", function () {
mockScope.$watch.mostRecentCall.args[1](mockDomainObject);
expect(controller.isRequestPending()).toBeTruthy();
@ -286,7 +320,6 @@ define(
expect(mockHandle.request.calls.length).toEqual(2);
});
it("maintains externally-provided domain axis bounds after data is received", function () {
mockSeries.getPointCount.andReturn(3);
mockSeries.getRangeValue.andReturn(42);