[Plot] Fill in specs

Fill in specs for elements used by the PlotController
in order to improve coverage of the plot bundle.
WTD-533.
This commit is contained in:
Victor Woeltjen 2014-12-02 10:11:46 -08:00
parent ae05ed903b
commit 2f475fc17a
8 changed files with 348 additions and 25 deletions

View File

@ -17,23 +17,18 @@ define(
min = [Number.POSITIVE_INFINITY, Number.POSITIVE_INFINITY],
x,
y,
xLabels = {},
yLabels = {},
yUnits = {},
domainOffset = Number.POSITIVE_INFINITY,
buffers;
datas = datas || [];
// Remove any undefined data sets
datas = (datas || []).filter(identity);
datas.filter(identity).forEach(function (data) {
// Filter out un
datas.forEach(function (data) {
domainOffset = Math.min(data.getDomainValue(0, domain), domainOffset);
});
datas.forEach(function (data, i) {
if (!data) {
return; // skip null data
}
vertices.push([]);
for (index = 0; index < data.getPointCount(); index = index + 1) {
x = data.getDomainValue(index, domain);
@ -45,18 +40,6 @@ define(
max[0] = Math.max(max[0], x);
max[1] = Math.max(max[1], y);
}
if (data.getDomainLabel) {
xLabels[data.getDomainLabel(domain)] = true;
}
if (data.getRangeLabel) {
yLabels[data.getRangeLabel(range)] = true;
}
if (data.getRangeUnits) {
yUnits[data.getRangeUnits(range)] = true;
}
});
if (max[1] === min[1]) {
@ -64,10 +47,6 @@ define(
min[1] = min[1] - 1.0;
}
xLabels = Object.keys(xLabels).sort();
yLabels = Object.keys(yLabels).sort();
yUnits = Object.keys(yUnits).sort();
buffers = vertices.map(function (v) { return new Float32Array(v); });
return {

View File

@ -9,6 +9,54 @@ define(
"use strict";
describe("A plot axis", function () {
var testMetadatas = [
{
tests: [
{ key: "t0", name: "T0" },
{ key: "t1", name: "T1" }
],
someKey: "some value"
},
{
tests: [
{ key: "t0", name: "T0" },
{ key: "t2", name: "T2" }
]
},
{
tests: [
{ key: "t3", name: "T3" },
{ key: "t4", name: "T4" },
{ key: "t5", name: "T5" },
{ key: "t6", name: "T6" }
]
}
],
testDefault = { key: "test", name: "Test" },
controller = new PlotAxis("tests", testMetadatas, testDefault);
it("pulls out a list of domain or range options", function () {
// Should have filtered out duplicates, etc
expect(controller.options).toEqual([
{ key: "t0", name: "T0" },
{ key: "t1", name: "T1" },
{ key: "t2", name: "T2" },
{ key: "t3", name: "T3" },
{ key: "t4", name: "T4" },
{ key: "t5", name: "T5" },
{ key: "t6", name: "T6" }
]);
});
it("chooses the first option as a default", function () {
expect(controller.active).toEqual({ key: "t0", name: "T0" });
});
it("falls back to a provided default if no options are present", function () {
expect(new PlotAxis("tests", [{}], testDefault).active)
.toEqual(testDefault);
});
});
}
);

View File

@ -9,6 +9,21 @@ define(
"use strict";
describe("The plot formatter", function () {
var formatter;
beforeEach(function () {
formatter = new PlotFormatter();
});
it("formats domains using YYYY-DDD style", function () {
expect(formatter.formatDomainValue(402513731000)).toEqual(
"1982-276 17:22:11"
);
});
it("formats ranges as values", function () {
expect(formatter.formatRangeValue(10)).toEqual("10.0");
});
});
}
);

View File

@ -9,6 +9,96 @@ define(
"use strict";
describe("The plot palette", function () {
it("can be used as a constructor", function () {
// PlotPalette has all static methods, so make
// sure it returns itself if used as a constructor.
expect(new PlotPalette()).toBe(PlotPalette);
});
it("has 30 unique colors in an integer format", function () {
// Integer format may be useful internal to the application.
// RGB 0-255
var i, j;
// Used to verify one of R, G, B in loop below
function verifyChannel(c) {
expect(typeof c).toEqual("number");
expect(c <= 255).toBeTruthy();
expect(c >= 0).toBeTruthy();
}
for (i = 0; i < 30; i += 1) {
// Verify that we got an array of numbers
expect(Array.isArray(PlotPalette.getIntegerColor(i)))
.toBeTruthy();
expect(PlotPalette.getIntegerColor(i).length).toEqual(3);
// Verify all three channels for type and range
PlotPalette.getIntegerColor(i).forEach(verifyChannel);
// Verify uniqueness
for (j = i + 1; j < 30; j += 1) {
expect(PlotPalette.getIntegerColor(i)).not.toEqual(
PlotPalette.getIntegerColor(j)
);
}
}
});
it("has 30 unique colors in a floating-point format", function () {
// Float format is useful to WebGL.
// RGB 0.0-1.1
var i, j;
// Used to verify one of R, G, B in loop below
function verifyChannel(c) {
expect(typeof c).toEqual("number");
expect(c <= 1.0).toBeTruthy();
expect(c >= 0.0).toBeTruthy();
}
for (i = 0; i < 30; i += 1) {
// Verify that we got an array of numbers
expect(Array.isArray(PlotPalette.getFloatColor(i)))
.toBeTruthy();
expect(PlotPalette.getFloatColor(i).length).toEqual(4);
// Verify all three channels for type and range
PlotPalette.getFloatColor(i).forEach(verifyChannel);
// Verify uniqueness
for (j = i + 1; j < 30; j += 1) {
expect(PlotPalette.getFloatColor(i)).not.toEqual(
PlotPalette.getFloatColor(j)
);
}
}
});
it("has 30 unique colors in a string format", function () {
// String format is useful in stylesheets
// #RRGGBB in hex
var i, j, c;
for (i = 0; i < 30; i += 1) {
c = PlotPalette.getStringColor(i);
// Verify that we #-style color strings
expect(typeof c).toEqual('string');
expect(c.length).toEqual(7);
expect(/^#[0-9a-fA-F]+$/.test(c)).toBeTruthy();
// Verify uniqueness
for (j = i + 1; j < 30; j += 1) {
expect(PlotPalette.getStringColor(i)).not.toEqual(
PlotPalette.getStringColor(j)
);
}
}
});
});
}
);

View File

@ -9,6 +9,72 @@ define(
"use strict";
describe("A plot pan-zoom stack", function () {
var panZoomStack,
initialOrigin,
initialDimensions,
otherOrigins,
otherDimensions;
// Shorthand for verifying getOrigin, getDimensions, and getPanZoom,
// which should always agree.
function verifyPanZoom(origin, dimensions) {
expect(panZoomStack.getOrigin()).toEqual(origin);
expect(panZoomStack.getDimensions()).toEqual(dimensions);
expect(panZoomStack.getPanZoom()).toEqual({
origin: origin,
dimensions: dimensions
});
}
beforeEach(function () {
initialOrigin = [ 4, 2 ];
initialDimensions = [ 600, 400 ];
otherOrigins = [ [8, 6], [12, 9] ];
otherDimensions = [ [400, 300], [200, 300] ];
panZoomStack =
new PlotPanZoomStack(initialOrigin, initialDimensions);
});
it("starts off reporting its initial values", function () {
verifyPanZoom(initialOrigin, initialDimensions);
});
it("allows origin/dimensions pairs to be pushed/popped", function () {
panZoomStack.pushPanZoom(otherOrigins[0], otherDimensions[0]);
verifyPanZoom(otherOrigins[0], otherDimensions[0]);
panZoomStack.pushPanZoom(otherOrigins[1], otherDimensions[1]);
verifyPanZoom(otherOrigins[1], otherDimensions[1]);
panZoomStack.popPanZoom();
verifyPanZoom(otherOrigins[0], otherDimensions[0]);
panZoomStack.popPanZoom();
verifyPanZoom(initialOrigin, initialDimensions);
});
it("reports current stack depth", function () {
expect(panZoomStack.getDepth()).toEqual(1);
panZoomStack.pushPanZoom(otherOrigins[0], otherDimensions[0]);
expect(panZoomStack.getDepth()).toEqual(2);
panZoomStack.pushPanZoom(otherOrigins[1], otherDimensions[1]);
expect(panZoomStack.getDepth()).toEqual(3);
});
it("allows base pan zoom to be restored", function () {
panZoomStack.pushPanZoom(otherOrigins[0], otherDimensions[0]);
panZoomStack.pushPanZoom(otherOrigins[1], otherDimensions[1]);
panZoomStack.clearPanZoom();
verifyPanZoom(initialOrigin, initialDimensions);
});
it("allows base pan zoom to be changed", function () {
panZoomStack.pushPanZoom(otherOrigins[0], otherDimensions[0]);
panZoomStack.setBasePanZoom(otherOrigins[1], otherDimensions[1]);
// Should not have changed current top-of-stack
verifyPanZoom(otherOrigins[0], otherDimensions[0]);
// Clear the stack - should be at our new base pan-zoom state
panZoomStack.clearPanZoom();
verifyPanZoom(otherOrigins[1], otherDimensions[1]);
});
});
}
);

View File

@ -9,6 +9,40 @@ define(
"use strict";
describe("A plot position", function () {
var mockPanZoom,
testOrigin = [ 10, 20 ],
testDimensions = [ 800, 10 ];
beforeEach(function () {
mockPanZoom = jasmine.createSpyObj(
"panZoomStack",
[ "getPanZoom" ]
);
mockPanZoom.getPanZoom.andReturn({
origin: testOrigin,
dimensions: testDimensions
});
});
it("transforms pixel coordinates to domain-range", function () {
var position = new PlotPosition(42, 450, 100, 1000, mockPanZoom);
// Domain: .42 * 800 + 10 = 346
// Range: .55 * 10 + 20 = 25.5
// Notably, y-axis is reversed between pixel space and range
expect(position.getPosition()).toEqual([346, 25.5]);
expect(position.getDomain()).toEqual(346);
expect(position.getRange()).toEqual(25.5);
});
it("treats a position as undefined if no pan-zoom state is present", function () {
var position;
mockPanZoom.getPanZoom.andReturn({});
position = new PlotPosition(1, 2, 100, 100, mockPanZoom);
expect(position.getDomain()).toBeUndefined();
expect(position.getRange()).toBeUndefined();
expect(position.getPosition()).toEqual([]);
});
});
}
);

View File

@ -8,7 +8,58 @@ define(
function (PlotPreparer) {
"use strict";
var START = 123456;
describe("A plot preparer", function () {
function makeMockData(scale) {
var mockData = jasmine.createSpyObj(
"data" + scale,
[ "getPointCount", "getDomainValue", "getRangeValue" ]
);
mockData.getPointCount.andReturn(1000);
mockData.getDomainValue.andCallFake(function (i) {
return START + i * 1000;
});
mockData.getRangeValue.andCallFake(function (i) {
return Math.sin(i / 100) * scale;
});
return mockData;
}
it("fits to provided data sets", function () {
var datas = [1, 2, 3].map(makeMockData),
preparer = new PlotPreparer(datas);
expect(preparer.getDomainOffset()).toEqual(START);
expect(preparer.getOrigin()[0]).toBeCloseTo(START, 3);
expect(preparer.getOrigin()[1]).toBeCloseTo(-3, 3);
expect(preparer.getDimensions()[0]).toBeCloseTo(999000, 3);
expect(preparer.getDimensions()[1]).toBeCloseTo(6, 3);
});
it("looks up values using a specified domain and range", function () {
var datas = [makeMockData(1)],
preparer = new PlotPreparer(datas, "testDomain", "testRange");
expect(datas[0].getDomainValue).toHaveBeenCalledWith(
jasmine.any(Number),
"testDomain"
);
expect(datas[0].getRangeValue).toHaveBeenCalledWith(
jasmine.any(Number),
"testRange"
);
});
it("provides a default range if data set is flat", function () {
var datas = [makeMockData(0)],
preparer = new PlotPreparer(datas);
expect(preparer.getDimensions[1]).not.toEqual(0);
});
});
}
);

View File

@ -9,6 +9,46 @@ define(
"use strict";
describe("A plot tick generator", function () {
var mockPanZoomStack,
mockFormatter,
generator;
beforeEach(function () {
mockPanZoomStack = jasmine.createSpyObj(
"panZoomStack",
[ "getPanZoom" ]
);
mockFormatter = jasmine.createSpyObj(
"formatter",
[ "formatDomainValue", "formatRangeValue" ]
);
mockPanZoomStack.getPanZoom.andReturn({
origin: [ 0, 0 ],
dimensions: [ 100, 100 ]
});
generator =
new PlotTickGenerator(mockPanZoomStack, mockFormatter);
});
it("provides tick marks for range", function () {
expect(generator.generateRangeTicks(11).length).toEqual(11);
// Should have used range formatter
expect(mockFormatter.formatRangeValue).toHaveBeenCalled();
expect(mockFormatter.formatDomainValue).not.toHaveBeenCalled();
});
it("provides tick marks for domain", function () {
expect(generator.generateDomainTicks(11).length).toEqual(11);
// Should have used domain formatter
expect(mockFormatter.formatRangeValue).not.toHaveBeenCalled();
expect(mockFormatter.formatDomainValue).toHaveBeenCalled();
});
});
}
);