Merge pull request #5462 from GaborFarkas/webgl_vector
WebGL vector support
This commit is contained in:
33
test/spec/ol/geom/flat/topologyflatgeom.test.js
Normal file
33
test/spec/ol/geom/flat/topologyflatgeom.test.js
Normal file
@@ -0,0 +1,33 @@
|
||||
goog.provide('ol.test.geom.flat.topology');
|
||||
|
||||
goog.require('ol.geom.flat.topology');
|
||||
|
||||
describe('ol.geom.flat.topology', function() {
|
||||
|
||||
describe('ol.geom.flat.topology.lineStringIsClosed', function() {
|
||||
|
||||
it('identifies closed lines aka boundaries', function() {
|
||||
var flatCoordinates = [0, 0, 3, 0, 0, 3, 0, 0];
|
||||
var isClosed = ol.geom.flat.topology.lineStringIsClosed(flatCoordinates, 0, flatCoordinates.length, 2);
|
||||
expect(isClosed).to.be(true);
|
||||
});
|
||||
|
||||
it('identifies regular linestrings', function() {
|
||||
var flatCoordinates = [0, 0, 3, 0, 0, 3, 5, 2];
|
||||
var isClosed = ol.geom.flat.topology.lineStringIsClosed(flatCoordinates, 0, flatCoordinates.length, 2);
|
||||
expect(isClosed).to.be(false);
|
||||
});
|
||||
|
||||
it('identifies degenerate boundaries', function() {
|
||||
var flatCoordinates = [0, 0, 3, 0, 0, 0];
|
||||
var isClosed = ol.geom.flat.topology.lineStringIsClosed(flatCoordinates, 0, flatCoordinates.length, 2);
|
||||
expect(isClosed).to.be(false);
|
||||
|
||||
flatCoordinates = [0, 0, 1, 1, 3, 3, 5, 5, 0, 0];
|
||||
isClosed = ol.geom.flat.topology.lineStringIsClosed(flatCoordinates, 0, flatCoordinates.length, 2);
|
||||
expect(isClosed).to.be(false);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
244
test/spec/ol/render/webgl/circlereplay.test.js
Normal file
244
test/spec/ol/render/webgl/circlereplay.test.js
Normal file
@@ -0,0 +1,244 @@
|
||||
goog.provide('ol.test.render.webgl.CircleReplay');
|
||||
|
||||
goog.require('ol');
|
||||
goog.require('ol.Feature');
|
||||
goog.require('ol.geom.Circle');
|
||||
goog.require('ol.render.webgl.circlereplay.defaultshader');
|
||||
goog.require('ol.render.webgl.CircleReplay');
|
||||
goog.require('ol.style.Fill');
|
||||
goog.require('ol.style.Stroke');
|
||||
|
||||
describe('ol.render.webgl.CircleReplay', function() {
|
||||
var replay;
|
||||
|
||||
var strokeStyle = new ol.style.Stroke({
|
||||
color: [0, 255, 0, 0.4]
|
||||
});
|
||||
|
||||
var fillStyle = new ol.style.Fill({
|
||||
color: [255, 0, 0, 1]
|
||||
});
|
||||
|
||||
beforeEach(function() {
|
||||
var tolerance = 0.1;
|
||||
var maxExtent = [-10000, -20000, 10000, 20000];
|
||||
replay = new ol.render.webgl.CircleReplay(tolerance, maxExtent);
|
||||
});
|
||||
|
||||
describe('#setFillStrokeStyle', function() {
|
||||
it('set expected states', function() {
|
||||
replay.setFillStrokeStyle(fillStyle, strokeStyle);
|
||||
expect(replay.state_).not.be(null);
|
||||
expect(replay.state_.strokeColor).to.eql([0, 1, 0, 0.4]);
|
||||
expect(replay.state_.lineWidth).to.be(1);
|
||||
expect(replay.state_.fillColor).to.eql([1, 0, 0, 1]);
|
||||
expect(replay.state_.changed).to.be(true);
|
||||
expect(replay.styles_).to.have.length(1);
|
||||
});
|
||||
|
||||
it('sets a transparent stroke, if none provided', function() {
|
||||
replay.setFillStrokeStyle(fillStyle, null);
|
||||
expect(replay.state_.strokeColor).to.eql([0, 0, 0, 0]);
|
||||
});
|
||||
|
||||
it('sets a transparent fill, if none provided', function() {
|
||||
replay.setFillStrokeStyle(null, strokeStyle);
|
||||
expect(replay.state_.fillColor).to.eql([0, 0, 0, 0]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#drawCircle', function() {
|
||||
it('sets the buffer data', function() {
|
||||
var circle = new ol.geom.Circle([0,0], 5000);
|
||||
|
||||
replay.setFillStrokeStyle(fillStyle, strokeStyle);
|
||||
replay.drawCircle(circle, null);
|
||||
expect(replay.vertices).to.have.length(16);
|
||||
expect(replay.indices).to.have.length(6);
|
||||
expect(replay.state_.changed).to.be(false);
|
||||
expect(replay.startIndices).to.have.length(1);
|
||||
expect(replay.startIndicesFeature).to.have.length(1);
|
||||
expect(replay.radius_).to.be(5000);
|
||||
});
|
||||
|
||||
it('does not draw if radius is zero', function() {
|
||||
var circle = new ol.geom.Circle([0,0], 0);
|
||||
|
||||
replay.drawCircle(circle, null);
|
||||
expect(replay.vertices).to.have.length(0);
|
||||
expect(replay.indices).to.have.length(0);
|
||||
expect(replay.startIndices).to.have.length(0);
|
||||
expect(replay.startIndicesFeature).to.have.length(0);
|
||||
});
|
||||
|
||||
it('resets state and removes style if it belongs to a zero radius circle', function() {
|
||||
var circle = new ol.geom.Circle([0,0], 0);
|
||||
|
||||
replay.setFillStrokeStyle(fillStyle, strokeStyle);
|
||||
replay.setFillStrokeStyle(null, strokeStyle);
|
||||
replay.drawCircle(circle, null);
|
||||
expect(replay.styles_).to.have.length(1);
|
||||
expect(replay.state_).not.be(null);
|
||||
expect(replay.state_.strokeColor).to.eql([0, 1, 0, 0.4]);
|
||||
expect(replay.state_.lineWidth).to.be(1);
|
||||
expect(replay.state_.fillColor).to.eql([1, 0, 0, 1]);
|
||||
expect(replay.state_.changed).to.be(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#drawCoordinates_', function() {
|
||||
it('envelopes the circle into a right isosceles triangle', function() {
|
||||
replay.radius_ = 5000;
|
||||
replay.drawCoordinates_([0, 0], 0, 2, 2);
|
||||
|
||||
expect(replay.vertices).to.eql([0, 0, 0, 5000, 0, 0, 1, 5000,
|
||||
0, 0, 2, 5000, 0, 0, 3, 5000]);
|
||||
expect(replay.indices).to.eql([0, 1, 2, 2, 3, 0]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#setUpProgram', function() {
|
||||
var context, gl;
|
||||
beforeEach(function() {
|
||||
context = {
|
||||
getProgram: function() {},
|
||||
useProgram: function() {}
|
||||
};
|
||||
gl = {
|
||||
enableVertexAttribArray: function() {},
|
||||
vertexAttribPointer: function() {},
|
||||
uniform1f: function() {},
|
||||
uniform2fv: function() {},
|
||||
getUniformLocation: function() {},
|
||||
getAttribLocation: function() {}
|
||||
};
|
||||
});
|
||||
|
||||
it('returns the locations used by the shaders', function() {
|
||||
var locations = replay.setUpProgram(gl, context, [2, 2], 1);
|
||||
expect(locations).to.be.a(
|
||||
ol.render.webgl.circlereplay.defaultshader.Locations);
|
||||
});
|
||||
|
||||
it('gets and compiles the shaders', function() {
|
||||
sinon.spy(context, 'getProgram');
|
||||
sinon.spy(context, 'useProgram');
|
||||
|
||||
replay.setUpProgram(gl, context, [2, 2], 1);
|
||||
expect(context.getProgram.calledWithExactly(
|
||||
ol.render.webgl.circlereplay.defaultshader.fragment,
|
||||
ol.render.webgl.circlereplay.defaultshader.vertex)).to.be(true);
|
||||
expect(context.useProgram.calledOnce).to.be(true);
|
||||
});
|
||||
|
||||
it('initializes the attrib pointers', function() {
|
||||
sinon.spy(gl, 'getAttribLocation');
|
||||
sinon.spy(gl, 'vertexAttribPointer');
|
||||
sinon.spy(gl, 'enableVertexAttribArray');
|
||||
|
||||
replay.setUpProgram(gl, context, [2, 2], 1);
|
||||
expect(gl.vertexAttribPointer.callCount).to.be(gl.getAttribLocation.callCount);
|
||||
expect(gl.enableVertexAttribArray.callCount).to.be(
|
||||
gl.getAttribLocation.callCount);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#shutDownProgram', function() {
|
||||
var context, gl;
|
||||
beforeEach(function() {
|
||||
context = {
|
||||
getProgram: function() {},
|
||||
useProgram: function() {}
|
||||
};
|
||||
gl = {
|
||||
enableVertexAttribArray: function() {},
|
||||
disableVertexAttribArray: function() {},
|
||||
vertexAttribPointer: function() {},
|
||||
uniform1f: function() {},
|
||||
uniform2fv: function() {},
|
||||
getUniformLocation: function() {},
|
||||
getAttribLocation: function() {}
|
||||
};
|
||||
});
|
||||
|
||||
it('disables the attrib pointers', function() {
|
||||
sinon.spy(gl, 'getAttribLocation');
|
||||
sinon.spy(gl, 'disableVertexAttribArray');
|
||||
|
||||
var locations = replay.setUpProgram(gl, context, [2, 2], 1);
|
||||
replay.shutDownProgram(gl, locations);
|
||||
expect(gl.disableVertexAttribArray.callCount).to.be(
|
||||
gl.getAttribLocation.callCount);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#drawReplay', function() {
|
||||
var gl, context;
|
||||
var feature1 = new ol.Feature({
|
||||
geometry: new ol.geom.Circle([0, 0], 5000)
|
||||
});
|
||||
var feature2 = new ol.Feature({
|
||||
geometry: new ol.geom.Circle([10, 10], 5000)
|
||||
});
|
||||
var feature3 = new ol.Feature({
|
||||
geometry: new ol.geom.Circle([20, 20], 5000)
|
||||
});
|
||||
beforeEach(function() {
|
||||
gl = {};
|
||||
context = {};
|
||||
replay.setFillStyle_ = function() {};
|
||||
replay.setStrokeStyle_ = function() {};
|
||||
replay.drawElements = function() {};
|
||||
sinon.spy(replay, 'setFillStyle_');
|
||||
sinon.spy(replay, 'setStrokeStyle_');
|
||||
sinon.spy(replay, 'drawElements');
|
||||
});
|
||||
|
||||
it('draws the elements in a single call if they have the same style', function() {
|
||||
replay.setFillStrokeStyle(fillStyle, strokeStyle);
|
||||
replay.drawCircle(feature1.getGeometry(), feature1);
|
||||
replay.setFillStrokeStyle(fillStyle, strokeStyle);
|
||||
replay.drawCircle(feature2.getGeometry(), feature2);
|
||||
replay.setFillStrokeStyle(fillStyle, strokeStyle);
|
||||
replay.drawCircle(feature3.getGeometry(), feature3);
|
||||
replay.startIndices.push(replay.indices.length);
|
||||
|
||||
replay.drawReplay(gl, context, {}, false);
|
||||
expect(replay.setFillStyle_.calledOnce).to.be(true);
|
||||
expect(replay.setStrokeStyle_.calledOnce).to.be(true);
|
||||
expect(replay.drawElements.calledOnce).to.be(true);
|
||||
});
|
||||
|
||||
it('draws the elements in batches if there are multiple styles', function() {
|
||||
replay.setFillStrokeStyle(fillStyle, strokeStyle);
|
||||
replay.drawCircle(feature1.getGeometry(), feature1);
|
||||
replay.setFillStrokeStyle(fillStyle, null);
|
||||
replay.drawCircle(feature2.getGeometry(), feature2);
|
||||
replay.setFillStrokeStyle(strokeStyle, null);
|
||||
replay.drawCircle(feature3.getGeometry(), feature3);
|
||||
replay.startIndices.push(replay.indices.length);
|
||||
|
||||
replay.drawReplay(gl, context, {}, false);
|
||||
expect(replay.setFillStyle_.calledThrice).to.be(true);
|
||||
expect(replay.setStrokeStyle_.calledThrice).to.be(true);
|
||||
expect(replay.drawElements.calledThrice).to.be(true);
|
||||
});
|
||||
|
||||
it('can skip elements if needed', function() {
|
||||
replay.setFillStrokeStyle(fillStyle, strokeStyle);
|
||||
replay.drawCircle(feature1.getGeometry(), feature1);
|
||||
replay.setFillStrokeStyle(fillStyle, strokeStyle);
|
||||
replay.drawCircle(feature2.getGeometry(), feature2);
|
||||
replay.setFillStrokeStyle(fillStyle, strokeStyle);
|
||||
replay.drawCircle(feature3.getGeometry(), feature3);
|
||||
replay.startIndices.push(replay.indices.length);
|
||||
var skippedFeatHash = {};
|
||||
skippedFeatHash[ol.getUid(feature2).toString()] = true;
|
||||
|
||||
replay.drawReplay(gl, context, skippedFeatHash, false);
|
||||
expect(replay.setFillStyle_.calledOnce).to.be(true);
|
||||
expect(replay.setStrokeStyle_.calledOnce).to.be(true);
|
||||
expect(replay.drawElements.calledTwice).to.be(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
245
test/spec/ol/render/webgl/imagereplay.test.js
Normal file
245
test/spec/ol/render/webgl/imagereplay.test.js
Normal file
@@ -0,0 +1,245 @@
|
||||
goog.provide('ol.test.render.webgl.ImageReplay');
|
||||
|
||||
goog.require('ol.geom.MultiPoint');
|
||||
goog.require('ol.geom.Point');
|
||||
goog.require('ol.render.webgl.imagereplay.defaultshader');
|
||||
goog.require('ol.render.webgl.ImageReplay');
|
||||
goog.require('ol.style.Image');
|
||||
|
||||
describe('ol.render.webgl.ImageReplay', function() {
|
||||
var replay;
|
||||
|
||||
var createImageStyle = function(image) {
|
||||
var imageStyle = new ol.style.Image({
|
||||
opacity: 0.1,
|
||||
rotateWithView: true,
|
||||
rotation: 1.5,
|
||||
scale: 2.0
|
||||
});
|
||||
imageStyle.getAnchor = function() {
|
||||
return [0.5, 1];
|
||||
};
|
||||
imageStyle.getImage = function() {
|
||||
return image;
|
||||
};
|
||||
imageStyle.getHitDetectionImage = function() {
|
||||
return image;
|
||||
};
|
||||
imageStyle.getImageSize = function() {
|
||||
return [512, 512];
|
||||
};
|
||||
imageStyle.getHitDetectionImageSize = function() {
|
||||
return [512, 512];
|
||||
};
|
||||
imageStyle.getOrigin = function() {
|
||||
return [200, 200];
|
||||
};
|
||||
imageStyle.getSize = function() {
|
||||
return [256, 256];
|
||||
};
|
||||
return imageStyle;
|
||||
};
|
||||
|
||||
beforeEach(function() {
|
||||
var tolerance = 0.1;
|
||||
var maxExtent = [-10000, -20000, 10000, 20000];
|
||||
replay = new ol.render.webgl.ImageReplay(tolerance, maxExtent);
|
||||
});
|
||||
|
||||
describe('#setImageStyle', function() {
|
||||
|
||||
var imageStyle1, imageStyle2;
|
||||
|
||||
beforeEach(function() {
|
||||
imageStyle1 = createImageStyle(new Image());
|
||||
imageStyle2 = createImageStyle(new Image());
|
||||
});
|
||||
|
||||
it('set expected states', function() {
|
||||
replay.setImageStyle(imageStyle1);
|
||||
expect(replay.anchorX_).to.be(0.5);
|
||||
expect(replay.anchorY_).to.be(1);
|
||||
expect(replay.height_).to.be(256);
|
||||
expect(replay.imageHeight_).to.be(512);
|
||||
expect(replay.imageWidth_).to.be(512);
|
||||
expect(replay.opacity_).to.be(0.1);
|
||||
expect(replay.originX_).to.be(200);
|
||||
expect(replay.originY_).to.be(200);
|
||||
expect(replay.rotation_).to.be(1.5);
|
||||
expect(replay.rotateWithView_).to.be(true);
|
||||
expect(replay.scale_).to.be(2.0);
|
||||
expect(replay.width_).to.be(256);
|
||||
expect(replay.images_).to.have.length(1);
|
||||
expect(replay.groupIndices_).to.have.length(0);
|
||||
expect(replay.hitDetectionImages_).to.have.length(1);
|
||||
expect(replay.hitDetectionGroupIndices_).to.have.length(0);
|
||||
|
||||
replay.setImageStyle(imageStyle1);
|
||||
expect(replay.images_).to.have.length(1);
|
||||
expect(replay.groupIndices_).to.have.length(0);
|
||||
expect(replay.hitDetectionImages_).to.have.length(1);
|
||||
expect(replay.hitDetectionGroupIndices_).to.have.length(0);
|
||||
|
||||
replay.setImageStyle(imageStyle2);
|
||||
expect(replay.images_).to.have.length(2);
|
||||
expect(replay.groupIndices_).to.have.length(1);
|
||||
expect(replay.hitDetectionImages_).to.have.length(2);
|
||||
expect(replay.hitDetectionGroupIndices_).to.have.length(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#drawPoint', function() {
|
||||
beforeEach(function() {
|
||||
var imageStyle = createImageStyle(new Image());
|
||||
replay.setImageStyle(imageStyle);
|
||||
});
|
||||
|
||||
it('sets the buffer data', function() {
|
||||
var point;
|
||||
|
||||
point = new ol.geom.Point([1000, 2000]);
|
||||
replay.drawPoint(point, null);
|
||||
expect(replay.vertices).to.have.length(32);
|
||||
expect(replay.indices).to.have.length(6);
|
||||
expect(replay.indices[0]).to.be(0);
|
||||
expect(replay.indices[1]).to.be(1);
|
||||
expect(replay.indices[2]).to.be(2);
|
||||
expect(replay.indices[3]).to.be(0);
|
||||
expect(replay.indices[4]).to.be(2);
|
||||
expect(replay.indices[5]).to.be(3);
|
||||
|
||||
point = new ol.geom.Point([2000, 3000]);
|
||||
replay.drawPoint(point, null);
|
||||
expect(replay.vertices).to.have.length(64);
|
||||
expect(replay.indices).to.have.length(12);
|
||||
expect(replay.indices[6]).to.be(4);
|
||||
expect(replay.indices[7]).to.be(5);
|
||||
expect(replay.indices[8]).to.be(6);
|
||||
expect(replay.indices[9]).to.be(4);
|
||||
expect(replay.indices[10]).to.be(6);
|
||||
expect(replay.indices[11]).to.be(7);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#drawMultiPoint', function() {
|
||||
beforeEach(function() {
|
||||
var imageStyle = createImageStyle(new Image());
|
||||
replay.setImageStyle(imageStyle);
|
||||
});
|
||||
|
||||
it('sets the buffer data', function() {
|
||||
var multiPoint;
|
||||
|
||||
multiPoint = new ol.geom.MultiPoint(
|
||||
[[1000, 2000], [2000, 3000]]);
|
||||
replay.drawMultiPoint(multiPoint, null);
|
||||
expect(replay.vertices).to.have.length(64);
|
||||
expect(replay.indices).to.have.length(12);
|
||||
expect(replay.indices[0]).to.be(0);
|
||||
expect(replay.indices[1]).to.be(1);
|
||||
expect(replay.indices[2]).to.be(2);
|
||||
expect(replay.indices[3]).to.be(0);
|
||||
expect(replay.indices[4]).to.be(2);
|
||||
expect(replay.indices[5]).to.be(3);
|
||||
expect(replay.indices[6]).to.be(4);
|
||||
expect(replay.indices[7]).to.be(5);
|
||||
expect(replay.indices[8]).to.be(6);
|
||||
expect(replay.indices[9]).to.be(4);
|
||||
expect(replay.indices[10]).to.be(6);
|
||||
expect(replay.indices[11]).to.be(7);
|
||||
|
||||
multiPoint = new ol.geom.MultiPoint(
|
||||
[[3000, 4000], [4000, 5000]]);
|
||||
replay.drawMultiPoint(multiPoint, null);
|
||||
expect(replay.vertices).to.have.length(128);
|
||||
expect(replay.indices).to.have.length(24);
|
||||
expect(replay.indices[12]).to.be(8);
|
||||
expect(replay.indices[13]).to.be(9);
|
||||
expect(replay.indices[14]).to.be(10);
|
||||
expect(replay.indices[15]).to.be(8);
|
||||
expect(replay.indices[16]).to.be(10);
|
||||
expect(replay.indices[17]).to.be(11);
|
||||
expect(replay.indices[18]).to.be(12);
|
||||
expect(replay.indices[19]).to.be(13);
|
||||
expect(replay.indices[20]).to.be(14);
|
||||
expect(replay.indices[21]).to.be(12);
|
||||
expect(replay.indices[22]).to.be(14);
|
||||
expect(replay.indices[23]).to.be(15);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#setUpProgram', function() {
|
||||
var context, gl;
|
||||
beforeEach(function() {
|
||||
context = {
|
||||
getProgram: function() {},
|
||||
useProgram: function() {}
|
||||
};
|
||||
gl = {
|
||||
enableVertexAttribArray: function() {},
|
||||
vertexAttribPointer: function() {},
|
||||
uniform1f: function() {},
|
||||
uniform2fv: function() {},
|
||||
getUniformLocation: function() {},
|
||||
getAttribLocation: function() {}
|
||||
};
|
||||
});
|
||||
|
||||
it('returns the locations used by the shaders', function() {
|
||||
var locations = replay.setUpProgram(gl, context, [2, 2], 1);
|
||||
expect(locations).to.be.a(
|
||||
ol.render.webgl.imagereplay.defaultshader.Locations);
|
||||
});
|
||||
|
||||
it('gets and compiles the shaders', function() {
|
||||
sinon.spy(context, 'getProgram');
|
||||
sinon.spy(context, 'useProgram');
|
||||
|
||||
replay.setUpProgram(gl, context, [2, 2], 1);
|
||||
expect(context.getProgram.calledWithExactly(
|
||||
ol.render.webgl.imagereplay.defaultshader.fragment,
|
||||
ol.render.webgl.imagereplay.defaultshader.vertex)).to.be(true);
|
||||
expect(context.useProgram.calledOnce).to.be(true);
|
||||
});
|
||||
|
||||
it('initializes the attrib pointers', function() {
|
||||
sinon.spy(gl, 'getAttribLocation');
|
||||
sinon.spy(gl, 'vertexAttribPointer');
|
||||
sinon.spy(gl, 'enableVertexAttribArray');
|
||||
|
||||
replay.setUpProgram(gl, context, [2, 2], 1);
|
||||
expect(gl.vertexAttribPointer.callCount).to.be(gl.getAttribLocation.callCount);
|
||||
expect(gl.enableVertexAttribArray.callCount).to.be(
|
||||
gl.getAttribLocation.callCount);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#shutDownProgram', function() {
|
||||
var context, gl;
|
||||
beforeEach(function() {
|
||||
context = {
|
||||
getProgram: function() {},
|
||||
useProgram: function() {}
|
||||
};
|
||||
gl = {
|
||||
enableVertexAttribArray: function() {},
|
||||
disableVertexAttribArray: function() {},
|
||||
vertexAttribPointer: function() {},
|
||||
uniform1f: function() {},
|
||||
uniform2fv: function() {},
|
||||
getUniformLocation: function() {},
|
||||
getAttribLocation: function() {}
|
||||
};
|
||||
});
|
||||
|
||||
it('disables the attrib pointers', function() {
|
||||
sinon.spy(gl, 'getAttribLocation');
|
||||
sinon.spy(gl, 'disableVertexAttribArray');
|
||||
|
||||
var locations = replay.setUpProgram(gl, context, [2, 2], 1);
|
||||
replay.shutDownProgram(gl, locations);
|
||||
expect(gl.disableVertexAttribArray.callCount).to.be(
|
||||
gl.getAttribLocation.callCount);
|
||||
});
|
||||
});
|
||||
});
|
||||
272
test/spec/ol/render/webgl/immediate.test.js
Normal file
272
test/spec/ol/render/webgl/immediate.test.js
Normal file
@@ -0,0 +1,272 @@
|
||||
goog.provide('ol.test.render.webgl.Immediate');
|
||||
|
||||
goog.require('ol.geom.GeometryCollection');
|
||||
goog.require('ol.geom.Circle');
|
||||
goog.require('ol.geom.Point');
|
||||
goog.require('ol.geom.MultiPoint');
|
||||
goog.require('ol.geom.LineString');
|
||||
goog.require('ol.geom.MultiLineString');
|
||||
goog.require('ol.geom.Polygon');
|
||||
goog.require('ol.geom.MultiPolygon');
|
||||
goog.require('ol.render.webgl.ImageReplay');
|
||||
goog.require('ol.render.webgl.CircleReplay');
|
||||
goog.require('ol.render.webgl.LineStringReplay');
|
||||
goog.require('ol.render.webgl.PolygonReplay');
|
||||
goog.require('ol.style.Circle');
|
||||
goog.require('ol.style.Fill');
|
||||
goog.require('ol.style.Stroke');
|
||||
goog.require('ol.style.Style');
|
||||
|
||||
describe('ol.render.webgl.Immediate', function() {
|
||||
var context, style, circle, line, multiLine, point, multiPoint, polygon, multiPolygon;
|
||||
beforeEach(function() {
|
||||
context = new ol.render.webgl.Immediate({}, [0, 0], 0, 0, [0, 0], [-180, -90, 180, 90], 1);
|
||||
style = new ol.style.Style({
|
||||
image: new ol.style.Circle(),
|
||||
fill: new ol.style.Fill(),
|
||||
stroke: new ol.style.Stroke()
|
||||
});
|
||||
circle = new ol.geom.Circle([0, 0], 5);
|
||||
line = new ol.geom.LineString([[0, 0], [5, 5]]);
|
||||
multiLine = new ol.geom.MultiLineString([[[0, 0], [5, 5]]]);
|
||||
point = new ol.geom.Point([0, 0]);
|
||||
multiPoint = new ol.geom.MultiPoint([[0, 0]]);
|
||||
polygon = new ol.geom.Polygon([[[0, 0], [5, 5], [5, 0], [0, 0]]]);
|
||||
multiPolygon = new ol.geom.MultiPolygon([[[[0, 0], [5, 5], [5, 0], [0, 0]]]]);
|
||||
});
|
||||
|
||||
describe('#setStyle', function() {
|
||||
it('sets the style of the context', function() {
|
||||
context.setStyle(style);
|
||||
expect(context.fillStyle_).to.be(style.getFill());
|
||||
expect(context.strokeStyle_).to.be(style.getStroke());
|
||||
expect(context.imageStyle_).to.be(style.getImage());
|
||||
});
|
||||
});
|
||||
|
||||
describe('#drawFeature', function() {
|
||||
var feat;
|
||||
beforeEach(function() {
|
||||
feat = new ol.Feature({
|
||||
geometry: circle
|
||||
});
|
||||
context.setStyle = function() {};
|
||||
context.drawGeometry = function() {};
|
||||
sinon.spy(context, 'setStyle');
|
||||
sinon.spy(context, 'drawGeometry');
|
||||
});
|
||||
|
||||
it('updates the style of the context', function() {
|
||||
context.drawFeature(feat, style);
|
||||
expect(context.setStyle.calledOnce).to.be(true);
|
||||
});
|
||||
|
||||
it('draws the geometry of the feature', function() {
|
||||
context.drawFeature(feat, style);
|
||||
expect(context.drawGeometry.calledOnce).to.be(true);
|
||||
});
|
||||
|
||||
it('does nothing if no geometry is provided', function() {
|
||||
feat = new ol.Feature();
|
||||
context.drawFeature(feat, style);
|
||||
expect(context.setStyle.called).to.be(false);
|
||||
expect(context.drawGeometry.called).to.be(false);
|
||||
});
|
||||
|
||||
it('does nothing if geometry is out of bounds', function() {
|
||||
feat = new ol.Feature({
|
||||
geometry: new ol.geom.Circle([540, 540], 1)
|
||||
});
|
||||
context.drawFeature(feat, style);
|
||||
expect(context.setStyle.called).to.be(false);
|
||||
expect(context.drawGeometry.called).to.be(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#drawGeometryCollection', function() {
|
||||
var geomColl;
|
||||
beforeEach(function() {
|
||||
geomColl = new ol.geom.GeometryCollection([circle, point, multiPoint,
|
||||
line, multiLine, polygon, multiPolygon]);
|
||||
});
|
||||
|
||||
it('draws every geometry in the collection', function() {
|
||||
context.drawGeometry = function() {};
|
||||
sinon.spy(context, 'drawGeometry');
|
||||
|
||||
context.drawGeometryCollection(geomColl);
|
||||
expect(context.drawGeometry.callCount).to.be(7);
|
||||
});
|
||||
});
|
||||
|
||||
describe('geometry functions', function() {
|
||||
function mock(ctor, geomFunc) {
|
||||
var tmpObj = {};
|
||||
tmpObj.replay = ctor.prototype.replay;
|
||||
ctor.prototype.replay = sinon.spy();
|
||||
tmpObj.finish = ctor.prototype.finish;
|
||||
ctor.prototype.finish = sinon.spy();
|
||||
tmpObj.getDeleteResourcesFunction = ctor.prototype.getDeleteResourcesFunction;
|
||||
ctor.prototype.getDeleteResourcesFunction = sinon.spy(function() {
|
||||
return function() {};
|
||||
});
|
||||
sinon.spy(ctor.prototype.getDeleteResourcesFunction);
|
||||
if (ctor === ol.render.webgl.ImageReplay) {
|
||||
tmpObj.setImageStyle = ctor.prototype.setImageStyle;
|
||||
ctor.prototype.setImageStyle = sinon.spy();
|
||||
} else {
|
||||
tmpObj.setFillStrokeStyle = ctor.prototype.setFillStrokeStyle;
|
||||
ctor.prototype.setFillStrokeStyle = sinon.spy();
|
||||
}
|
||||
tmpObj[geomFunc] = ctor.prototype[geomFunc];
|
||||
ctor.prototype[geomFunc] = sinon.spy();
|
||||
return tmpObj;
|
||||
}
|
||||
|
||||
function restore(ctor, tmpObj) {
|
||||
for (var i in tmpObj) {
|
||||
ctor.prototype[i] = tmpObj[i];
|
||||
}
|
||||
}
|
||||
|
||||
describe('#drawPoint', function() {
|
||||
var tmpObj;
|
||||
beforeEach(function() {
|
||||
tmpObj = mock(ol.render.webgl.ImageReplay, 'drawPoint');
|
||||
});
|
||||
|
||||
it('draws a point', function() {
|
||||
context.drawGeometry(point);
|
||||
expect(ol.render.webgl.ImageReplay.prototype.setImageStyle.calledOnce).to.be(true);
|
||||
expect(ol.render.webgl.ImageReplay.prototype.drawPoint.calledOnce).to.be(true);
|
||||
expect(ol.render.webgl.ImageReplay.prototype.finish.calledOnce).to.be(true);
|
||||
expect(ol.render.webgl.ImageReplay.prototype.replay.calledOnce).to.be(true);
|
||||
expect(ol.render.webgl.ImageReplay.prototype.getDeleteResourcesFunction.calledOnce).to.be(true);
|
||||
});
|
||||
|
||||
after(function() {
|
||||
restore(ol.render.webgl.ImageReplay, tmpObj);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#drawMultiPoint', function() {
|
||||
var tmpObj;
|
||||
beforeEach(function() {
|
||||
tmpObj = mock(ol.render.webgl.ImageReplay, 'drawMultiPoint');
|
||||
});
|
||||
|
||||
it('draws a multi point', function() {
|
||||
context.drawGeometry(multiPoint);
|
||||
expect(ol.render.webgl.ImageReplay.prototype.setImageStyle.calledOnce).to.be(true);
|
||||
expect(ol.render.webgl.ImageReplay.prototype.drawMultiPoint.calledOnce).to.be(true);
|
||||
expect(ol.render.webgl.ImageReplay.prototype.finish.calledOnce).to.be(true);
|
||||
expect(ol.render.webgl.ImageReplay.prototype.replay.calledOnce).to.be(true);
|
||||
expect(ol.render.webgl.ImageReplay.prototype.getDeleteResourcesFunction.calledOnce).to.be(true);
|
||||
});
|
||||
|
||||
after(function() {
|
||||
restore(ol.render.webgl.ImageReplay, tmpObj);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#drawLineString', function() {
|
||||
var tmpObj;
|
||||
beforeEach(function() {
|
||||
tmpObj = mock(ol.render.webgl.LineStringReplay, 'drawLineString');
|
||||
});
|
||||
|
||||
it('draws a line string', function() {
|
||||
context.drawGeometry(line);
|
||||
expect(ol.render.webgl.LineStringReplay.prototype.setFillStrokeStyle.calledOnce).to.be(true);
|
||||
expect(ol.render.webgl.LineStringReplay.prototype.drawLineString.calledOnce).to.be(true);
|
||||
expect(ol.render.webgl.LineStringReplay.prototype.finish.calledOnce).to.be(true);
|
||||
expect(ol.render.webgl.LineStringReplay.prototype.replay.calledOnce).to.be(true);
|
||||
expect(ol.render.webgl.LineStringReplay.prototype.getDeleteResourcesFunction.calledOnce).to.be(true);
|
||||
});
|
||||
|
||||
after(function() {
|
||||
restore(ol.render.webgl.LineStringReplay, tmpObj);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#drawMultiLineString', function() {
|
||||
var tmpObj;
|
||||
beforeEach(function() {
|
||||
tmpObj = mock(ol.render.webgl.LineStringReplay, 'drawMultiLineString');
|
||||
});
|
||||
|
||||
it('draws a multi line string', function() {
|
||||
context.drawGeometry(multiLine);
|
||||
expect(ol.render.webgl.LineStringReplay.prototype.setFillStrokeStyle.calledOnce).to.be(true);
|
||||
expect(ol.render.webgl.LineStringReplay.prototype.drawMultiLineString.calledOnce).to.be(true);
|
||||
expect(ol.render.webgl.LineStringReplay.prototype.finish.calledOnce).to.be(true);
|
||||
expect(ol.render.webgl.LineStringReplay.prototype.replay.calledOnce).to.be(true);
|
||||
expect(ol.render.webgl.LineStringReplay.prototype.getDeleteResourcesFunction.calledOnce).to.be(true);
|
||||
});
|
||||
|
||||
after(function() {
|
||||
restore(ol.render.webgl.LineStringReplay, tmpObj);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#drawPolygon', function() {
|
||||
var tmpObj;
|
||||
beforeEach(function() {
|
||||
tmpObj = mock(ol.render.webgl.PolygonReplay, 'drawPolygon');
|
||||
});
|
||||
|
||||
it('draws a polygon', function() {
|
||||
context.drawGeometry(polygon);
|
||||
expect(ol.render.webgl.PolygonReplay.prototype.setFillStrokeStyle.calledOnce).to.be(true);
|
||||
expect(ol.render.webgl.PolygonReplay.prototype.drawPolygon.calledOnce).to.be(true);
|
||||
expect(ol.render.webgl.PolygonReplay.prototype.finish.calledOnce).to.be(true);
|
||||
expect(ol.render.webgl.PolygonReplay.prototype.replay.calledOnce).to.be(true);
|
||||
expect(ol.render.webgl.PolygonReplay.prototype.getDeleteResourcesFunction.calledOnce).to.be(true);
|
||||
});
|
||||
|
||||
after(function() {
|
||||
restore(ol.render.webgl.PolygonReplay, tmpObj);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#drawMultiPolygon', function() {
|
||||
var tmpObj;
|
||||
beforeEach(function() {
|
||||
tmpObj = mock(ol.render.webgl.PolygonReplay, 'drawMultiPolygon');
|
||||
});
|
||||
|
||||
it('draws a multi polygon', function() {
|
||||
context.drawGeometry(multiPolygon);
|
||||
expect(ol.render.webgl.PolygonReplay.prototype.setFillStrokeStyle.calledOnce).to.be(true);
|
||||
expect(ol.render.webgl.PolygonReplay.prototype.drawMultiPolygon.calledOnce).to.be(true);
|
||||
expect(ol.render.webgl.PolygonReplay.prototype.finish.calledOnce).to.be(true);
|
||||
expect(ol.render.webgl.PolygonReplay.prototype.replay.calledOnce).to.be(true);
|
||||
expect(ol.render.webgl.PolygonReplay.prototype.getDeleteResourcesFunction.calledOnce).to.be(true);
|
||||
});
|
||||
|
||||
after(function() {
|
||||
restore(ol.render.webgl.PolygonReplay, tmpObj);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#drawCircle', function() {
|
||||
var tmpObj;
|
||||
beforeEach(function() {
|
||||
tmpObj = mock(ol.render.webgl.CircleReplay, 'drawCircle');
|
||||
});
|
||||
|
||||
it('draws a circle', function() {
|
||||
context.drawGeometry(circle);
|
||||
expect(ol.render.webgl.CircleReplay.prototype.setFillStrokeStyle.calledOnce).to.be(true);
|
||||
expect(ol.render.webgl.CircleReplay.prototype.drawCircle.calledOnce).to.be(true);
|
||||
expect(ol.render.webgl.CircleReplay.prototype.finish.calledOnce).to.be(true);
|
||||
expect(ol.render.webgl.CircleReplay.prototype.replay.calledOnce).to.be(true);
|
||||
expect(ol.render.webgl.CircleReplay.prototype.getDeleteResourcesFunction.calledOnce).to.be(true);
|
||||
});
|
||||
|
||||
after(function() {
|
||||
restore(ol.render.webgl.CircleReplay, tmpObj);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
62
test/spec/ol/render/webgl/index.test.js
Normal file
62
test/spec/ol/render/webgl/index.test.js
Normal file
@@ -0,0 +1,62 @@
|
||||
goog.provide('ol.test.render.webgl.Replay');
|
||||
|
||||
goog.require('ol.render.webgl.Replay');
|
||||
|
||||
describe('ol.render.Replay', function() {
|
||||
var replay;
|
||||
beforeEach(function() {
|
||||
replay = new ol.render.webgl.Replay(5, [-180, -90, 180, 90]);
|
||||
});
|
||||
|
||||
|
||||
describe('constructor', function() {
|
||||
it('stores view related data', function() {
|
||||
expect(replay.tolerance).to.be(5);
|
||||
expect(replay.maxExtent).to.eql([-180, -90, 180, 90]);
|
||||
expect(replay.origin).to.eql([0, 0]);
|
||||
});
|
||||
|
||||
it ('sets up the required matrices', function() {
|
||||
var mat3 = [1, 0, 0, 1, 0, 0];
|
||||
var mat4 = [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1];
|
||||
expect(replay.projectionMatrix_).to.eql(mat3);
|
||||
expect(replay.offsetRotateMatrix_).to.eql(mat3);
|
||||
expect(replay.offsetScaleMatrix_).to.eql(mat3);
|
||||
expect(replay.tmpMat4_).to.eql(mat4);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#replay', function() {
|
||||
var gl = {
|
||||
uniformMatrix4fv: function() {},
|
||||
uniform1f: function() {}
|
||||
};
|
||||
var context = {
|
||||
bindBuffer: function() {},
|
||||
getGL: function() {
|
||||
return gl;
|
||||
}
|
||||
};
|
||||
beforeEach(function() {
|
||||
replay.setUpProgram = function() {
|
||||
return {
|
||||
u_projectionMatrix: true,
|
||||
u_offsetScaleMatrix: true,
|
||||
u_offsetRotateMatrix: true,
|
||||
u_opacity: true
|
||||
};
|
||||
};
|
||||
});
|
||||
|
||||
it('calculates the correct matrices', function() {
|
||||
var sin = Math.sin(Math.PI);
|
||||
replay.replay(context, [0, 0], 10, Math.PI, [10, 10], 1, 0, {}, undefined,
|
||||
false, undefined);
|
||||
|
||||
expect(replay.projectionMatrix_).to.eql([-0.02, -sin * 0.02, sin * 0.02,
|
||||
-0.02, 0, 0]);
|
||||
expect(replay.offsetRotateMatrix_).to.eql([-1, -sin, sin, -1, 0, 0]);
|
||||
expect(replay.offsetScaleMatrix_).to.eql([0.2, 0, 0, 0.2, 0, 0]);
|
||||
});
|
||||
});
|
||||
});
|
||||
363
test/spec/ol/render/webgl/linestringreplay.test.js
Normal file
363
test/spec/ol/render/webgl/linestringreplay.test.js
Normal file
@@ -0,0 +1,363 @@
|
||||
goog.provide('ol.test.render.webgl.LineStringReplay');
|
||||
|
||||
goog.require('ol');
|
||||
goog.require('ol.Feature');
|
||||
goog.require('ol.geom.LineString');
|
||||
goog.require('ol.geom.MultiLineString');
|
||||
goog.require('ol.render.webgl.linestringreplay.defaultshader');
|
||||
goog.require('ol.render.webgl.LineStringReplay');
|
||||
goog.require('ol.style.Stroke');
|
||||
|
||||
describe('ol.render.webgl.LineStringReplay', function() {
|
||||
var replay;
|
||||
|
||||
var strokeStyle1 = new ol.style.Stroke({
|
||||
color: [0, 255, 0, 0.4]
|
||||
});
|
||||
|
||||
var strokeStyle2 = new ol.style.Stroke({
|
||||
color: [255, 0, 0, 1],
|
||||
lineCap: 'square',
|
||||
lineJoin: 'miter'
|
||||
});
|
||||
|
||||
beforeEach(function() {
|
||||
var tolerance = 0.1;
|
||||
var maxExtent = [-10000, -20000, 10000, 20000];
|
||||
replay = new ol.render.webgl.LineStringReplay(tolerance, maxExtent);
|
||||
});
|
||||
|
||||
describe('#setFillStrokeStyle', function() {
|
||||
|
||||
it('set expected states', function() {
|
||||
replay.setFillStrokeStyle(null, strokeStyle1);
|
||||
expect(replay.state_).not.be(null);
|
||||
expect(replay.state_.lineCap).to.be('round');
|
||||
expect(replay.state_.lineJoin).to.be('round');
|
||||
expect(replay.state_.strokeColor).to.eql([0, 1, 0, 0.4]);
|
||||
expect(replay.state_.lineWidth).to.be(1);
|
||||
expect(replay.state_.miterLimit).to.be(10);
|
||||
expect(replay.state_.changed).to.be(true);
|
||||
expect(replay.styles_).to.have.length(1);
|
||||
|
||||
replay.setFillStrokeStyle(null, strokeStyle2);
|
||||
expect(replay.state_.lineCap).to.be('square');
|
||||
expect(replay.state_.lineJoin).to.be('miter');
|
||||
expect(replay.state_.strokeColor).to.eql([1, 0, 0, 1]);
|
||||
expect(replay.state_.lineWidth).to.be(1);
|
||||
expect(replay.state_.miterLimit).to.be(10);
|
||||
expect(replay.state_.changed).to.be(true);
|
||||
expect(replay.styles_).to.have.length(2);
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
describe('#drawLineString', function() {
|
||||
|
||||
it('sets the buffer data', function() {
|
||||
var linestring;
|
||||
|
||||
linestring = new ol.geom.LineString(
|
||||
[[1000, 2000], [2000, 3000]]);
|
||||
replay.setFillStrokeStyle(null, strokeStyle1);
|
||||
replay.drawLineString(linestring, null);
|
||||
expect(replay.vertices).to.have.length(56);
|
||||
expect(replay.indices).to.have.length(18);
|
||||
expect(replay.state_.changed).to.be(false);
|
||||
expect(replay.startIndices).to.have.length(1);
|
||||
expect(replay.startIndicesFeature).to.have.length(1);
|
||||
|
||||
linestring = new ol.geom.LineString(
|
||||
[[1000, 3000], [2000, 4000], [3000, 3000]]);
|
||||
replay.drawLineString(linestring, null);
|
||||
expect(replay.vertices).to.have.length(140);
|
||||
expect(replay.indices).to.have.length(48);
|
||||
expect(replay.state_.changed).to.be(false);
|
||||
expect(replay.startIndices).to.have.length(2);
|
||||
expect(replay.startIndicesFeature).to.have.length(2);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#drawMultiLineString', function() {
|
||||
|
||||
it('sets the buffer data', function() {
|
||||
var multilinestring;
|
||||
|
||||
multilinestring = new ol.geom.MultiLineString(
|
||||
[[[1000, 2000], [2000, 3000]],
|
||||
[[1000, 3000], [2000, 4000], [3000, 3000]]]);
|
||||
replay.setFillStrokeStyle(null, strokeStyle1);
|
||||
replay.drawMultiLineString(multilinestring, null);
|
||||
expect(replay.vertices).to.have.length(140);
|
||||
expect(replay.indices).to.have.length(48);
|
||||
expect(replay.state_.changed).to.be(false);
|
||||
expect(replay.startIndices).to.have.length(1);
|
||||
expect(replay.startIndicesFeature).to.have.length(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#drawCoordinates_', function() {
|
||||
|
||||
it('triangulates linestrings', function() {
|
||||
var linestring;
|
||||
|
||||
var stroke = new ol.style.Stroke({
|
||||
color: [0, 255, 0, 1],
|
||||
lineCap: 'butt',
|
||||
lineJoin: 'bevel'
|
||||
});
|
||||
|
||||
linestring = new ol.geom.LineString(
|
||||
[[1000, 3000], [2000, 4000], [3000, 3000]]);
|
||||
var flatCoordinates = linestring.getFlatCoordinates();
|
||||
replay.setFillStrokeStyle(null, stroke);
|
||||
replay.drawCoordinates_(flatCoordinates, 0,
|
||||
flatCoordinates.length, 2);
|
||||
expect(replay.indices).to.eql(
|
||||
[2, 0, 1, 4, 2, 1,
|
||||
2, 4, 3,
|
||||
5, 3, 4, 4, 6, 5]);
|
||||
});
|
||||
|
||||
it('optionally creates miters', function() {
|
||||
var linestring;
|
||||
|
||||
var stroke = new ol.style.Stroke({
|
||||
color: [0, 255, 0, 1],
|
||||
lineCap: 'butt'
|
||||
});
|
||||
|
||||
linestring = new ol.geom.LineString(
|
||||
[[1000, 3000], [2000, 4000], [3000, 3000]]);
|
||||
var flatCoordinates = linestring.getFlatCoordinates();
|
||||
replay.setFillStrokeStyle(null, stroke);
|
||||
replay.drawCoordinates_(flatCoordinates, 0,
|
||||
flatCoordinates.length, 2);
|
||||
expect(replay.indices).to.eql(
|
||||
[2, 0, 1, 4, 2, 1,
|
||||
2, 4, 3, 3, 5, 2,
|
||||
6, 3, 4, 4, 7, 6]);
|
||||
});
|
||||
|
||||
it('optionally creates caps', function() {
|
||||
var linestring;
|
||||
|
||||
var stroke = new ol.style.Stroke({
|
||||
color: [0, 255, 0, 1]
|
||||
});
|
||||
|
||||
linestring = new ol.geom.LineString(
|
||||
[[1000, 3000], [2000, 4000], [3000, 3000]]);
|
||||
var flatCoordinates = linestring.getFlatCoordinates();
|
||||
replay.setFillStrokeStyle(null, stroke);
|
||||
replay.drawCoordinates_(flatCoordinates, 0,
|
||||
flatCoordinates.length, 2);
|
||||
expect(replay.indices).to.eql(
|
||||
[2, 0, 1, 1, 3, 2,
|
||||
4, 2, 3, 6, 4, 3,
|
||||
4, 6, 5, 5, 7, 4,
|
||||
8, 5, 6, 6, 9, 8,
|
||||
10, 8, 9, 9, 11, 10]);
|
||||
});
|
||||
|
||||
it('respects segment orientation', function() {
|
||||
var linestring;
|
||||
|
||||
var stroke = new ol.style.Stroke({
|
||||
color: [0, 255, 0, 1],
|
||||
lineCap: 'butt',
|
||||
lineJoin: 'bevel'
|
||||
});
|
||||
|
||||
linestring = new ol.geom.LineString(
|
||||
[[1000, 3000], [2000, 2000], [3000, 3000]]);
|
||||
var flatCoordinates = linestring.getFlatCoordinates();
|
||||
replay.setFillStrokeStyle(null, stroke);
|
||||
replay.drawCoordinates_(flatCoordinates, 0,
|
||||
flatCoordinates.length, 2);
|
||||
expect(replay.indices).to.eql(
|
||||
[2, 0, 1, 4, 2, 0,
|
||||
2, 4, 3,
|
||||
5, 3, 4, 4, 6, 5]);
|
||||
});
|
||||
|
||||
it('closes boundaries', function() {
|
||||
var linestring;
|
||||
|
||||
var stroke = new ol.style.Stroke({
|
||||
color: [0, 255, 0, 1],
|
||||
lineCap: 'butt',
|
||||
lineJoin: 'bevel'
|
||||
});
|
||||
|
||||
linestring = new ol.geom.LineString(
|
||||
[[1000, 3000], [2000, 4000], [3000, 3000], [1000, 3000]]);
|
||||
var flatCoordinates = linestring.getFlatCoordinates();
|
||||
replay.setFillStrokeStyle(null, stroke);
|
||||
replay.drawCoordinates_(flatCoordinates, 0,
|
||||
flatCoordinates.length, 2);
|
||||
expect(replay.indices).to.eql(
|
||||
[0, 2, 1, 3, 1, 2,
|
||||
5, 3, 2,
|
||||
3, 5, 4, 6, 4, 5,
|
||||
8, 6, 5,
|
||||
6, 8, 7, 9, 7, 8,
|
||||
10, 9, 8]);
|
||||
expect(replay.vertices.slice(0, 7)).to.eql(
|
||||
replay.vertices.slice(-14, -7));
|
||||
expect(replay.vertices.slice(14, 21)).to.eql(
|
||||
replay.vertices.slice(-7));
|
||||
});
|
||||
});
|
||||
|
||||
describe('#setUpProgram', function() {
|
||||
var context, gl;
|
||||
beforeEach(function() {
|
||||
context = {
|
||||
getProgram: function() {},
|
||||
useProgram: function() {}
|
||||
};
|
||||
gl = {
|
||||
enableVertexAttribArray: function() {},
|
||||
vertexAttribPointer: function() {},
|
||||
uniform1f: function() {},
|
||||
uniform2fv: function() {},
|
||||
getUniformLocation: function() {},
|
||||
getAttribLocation: function() {}
|
||||
};
|
||||
});
|
||||
|
||||
it('returns the locations used by the shaders', function() {
|
||||
var locations = replay.setUpProgram(gl, context, [2, 2], 1);
|
||||
expect(locations).to.be.a(
|
||||
ol.render.webgl.linestringreplay.defaultshader.Locations);
|
||||
});
|
||||
|
||||
it('gets and compiles the shaders', function() {
|
||||
sinon.spy(context, 'getProgram');
|
||||
sinon.spy(context, 'useProgram');
|
||||
|
||||
replay.setUpProgram(gl, context, [2, 2], 1);
|
||||
expect(context.getProgram.calledWithExactly(
|
||||
ol.render.webgl.linestringreplay.defaultshader.fragment,
|
||||
ol.render.webgl.linestringreplay.defaultshader.vertex)).to.be(true);
|
||||
expect(context.useProgram.calledOnce).to.be(true);
|
||||
});
|
||||
|
||||
it('initializes the attrib pointers', function() {
|
||||
sinon.spy(gl, 'getAttribLocation');
|
||||
sinon.spy(gl, 'vertexAttribPointer');
|
||||
sinon.spy(gl, 'enableVertexAttribArray');
|
||||
|
||||
replay.setUpProgram(gl, context, [2, 2], 1);
|
||||
expect(gl.vertexAttribPointer.callCount).to.be(gl.getAttribLocation.callCount);
|
||||
expect(gl.enableVertexAttribArray.callCount).to.be(
|
||||
gl.getAttribLocation.callCount);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#shutDownProgram', function() {
|
||||
var context, gl;
|
||||
beforeEach(function() {
|
||||
context = {
|
||||
getProgram: function() {},
|
||||
useProgram: function() {}
|
||||
};
|
||||
gl = {
|
||||
enableVertexAttribArray: function() {},
|
||||
disableVertexAttribArray: function() {},
|
||||
vertexAttribPointer: function() {},
|
||||
uniform1f: function() {},
|
||||
uniform2fv: function() {},
|
||||
getUniformLocation: function() {},
|
||||
getAttribLocation: function() {}
|
||||
};
|
||||
});
|
||||
|
||||
it('disables the attrib pointers', function() {
|
||||
sinon.spy(gl, 'getAttribLocation');
|
||||
sinon.spy(gl, 'disableVertexAttribArray');
|
||||
|
||||
var locations = replay.setUpProgram(gl, context, [2, 2], 1);
|
||||
replay.shutDownProgram(gl, locations);
|
||||
expect(gl.disableVertexAttribArray.callCount).to.be(
|
||||
gl.getAttribLocation.callCount);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#drawReplay', function() {
|
||||
var gl, context;
|
||||
var feature1 = new ol.Feature({
|
||||
geometry: new ol.geom.LineString([[0, 0], [500, 500]])
|
||||
});
|
||||
var feature2 = new ol.Feature({
|
||||
geometry: new ol.geom.LineString([[0, 0], [500, 500]])
|
||||
});
|
||||
var feature3 = new ol.Feature({
|
||||
geometry: new ol.geom.LineString([[0, 0], [500, 500]])
|
||||
});
|
||||
beforeEach(function() {
|
||||
gl = {
|
||||
enable: function() {},
|
||||
disable: function() {},
|
||||
depthMask: function() {},
|
||||
depthFunc: function() {},
|
||||
clear: function() {},
|
||||
getParameter: function() {}
|
||||
};
|
||||
context = {};
|
||||
replay.setStrokeStyle_ = function() {};
|
||||
replay.drawElements = function() {};
|
||||
sinon.spy(replay, 'setStrokeStyle_');
|
||||
sinon.spy(replay, 'drawElements');
|
||||
sinon.spy(gl, 'clear');
|
||||
});
|
||||
|
||||
it('draws the elements in a single call if they have the same style', function() {
|
||||
replay.setFillStrokeStyle(null, strokeStyle1);
|
||||
replay.drawLineString(feature1.getGeometry(), feature1);
|
||||
replay.setFillStrokeStyle(null, strokeStyle1);
|
||||
replay.drawLineString(feature2.getGeometry(), feature2);
|
||||
replay.setFillStrokeStyle(null, strokeStyle1);
|
||||
replay.drawLineString(feature3.getGeometry(), feature3);
|
||||
replay.startIndices.push(replay.indices.length);
|
||||
|
||||
replay.drawReplay(gl, context, {}, false);
|
||||
expect(replay.setStrokeStyle_.calledOnce).to.be(true);
|
||||
expect(replay.drawElements.calledOnce).to.be(true);
|
||||
expect(gl.clear.called).to.be(true);
|
||||
});
|
||||
|
||||
it('draws the elements in batches if there are multiple styles', function() {
|
||||
replay.setFillStrokeStyle(null, strokeStyle1);
|
||||
replay.drawLineString(feature1.getGeometry(), feature1);
|
||||
replay.setFillStrokeStyle(null, strokeStyle2);
|
||||
replay.drawLineString(feature2.getGeometry(), feature2);
|
||||
replay.setFillStrokeStyle(null, strokeStyle1);
|
||||
replay.drawLineString(feature3.getGeometry(), feature3);
|
||||
replay.startIndices.push(replay.indices.length);
|
||||
|
||||
replay.drawReplay(gl, context, {}, false);
|
||||
expect(replay.setStrokeStyle_.calledThrice).to.be(true);
|
||||
expect(replay.drawElements.calledThrice).to.be(true);
|
||||
expect(gl.clear.called).to.be(true);
|
||||
});
|
||||
|
||||
it('can skip elements if needed', function() {
|
||||
replay.setFillStrokeStyle(null, strokeStyle1);
|
||||
replay.drawLineString(feature1.getGeometry(), feature1);
|
||||
replay.setFillStrokeStyle(null, strokeStyle1);
|
||||
replay.drawLineString(feature2.getGeometry(), feature2);
|
||||
replay.setFillStrokeStyle(null, strokeStyle1);
|
||||
replay.drawLineString(feature3.getGeometry(), feature3);
|
||||
replay.startIndices.push(replay.indices.length);
|
||||
var skippedFeatHash = {};
|
||||
skippedFeatHash[ol.getUid(feature2).toString()] = true;
|
||||
|
||||
replay.drawReplay(gl, context, skippedFeatHash, false);
|
||||
expect(replay.setStrokeStyle_.calledOnce).to.be(true);
|
||||
expect(replay.drawElements.calledTwice).to.be(true);
|
||||
expect(gl.clear.called).to.be(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
471
test/spec/ol/render/webgl/polygonreplay.test.js
Normal file
471
test/spec/ol/render/webgl/polygonreplay.test.js
Normal file
@@ -0,0 +1,471 @@
|
||||
goog.provide('ol.test.render.webgl.PolygonReplay');
|
||||
|
||||
goog.require('ol');
|
||||
goog.require('ol.Feature');
|
||||
goog.require('ol.geom.MultiPolygon');
|
||||
goog.require('ol.geom.Polygon');
|
||||
goog.require('ol.render.webgl.polygonreplay.defaultshader');
|
||||
goog.require('ol.render.webgl.PolygonReplay');
|
||||
goog.require('ol.structs.LinkedList');
|
||||
goog.require('ol.structs.RBush');
|
||||
goog.require('ol.style.Fill');
|
||||
goog.require('ol.style.Stroke');
|
||||
|
||||
describe('ol.render.webgl.PolygonReplay', function() {
|
||||
var replay;
|
||||
|
||||
var fillStyle = new ol.style.Fill({
|
||||
color: [0, 0, 255, 0.5]
|
||||
});
|
||||
var strokeStyle = new ol.style.Stroke({
|
||||
color: [0, 255, 0, 0.4]
|
||||
});
|
||||
|
||||
beforeEach(function() {
|
||||
var tolerance = 0.1;
|
||||
var maxExtent = [-10000, -20000, 10000, 20000];
|
||||
replay = new ol.render.webgl.PolygonReplay(tolerance, maxExtent);
|
||||
});
|
||||
|
||||
describe('#drawPolygon', function() {
|
||||
beforeEach(function() {
|
||||
replay.setFillStrokeStyle(fillStyle, strokeStyle);
|
||||
});
|
||||
|
||||
it('sets the buffer data', function() {
|
||||
var polygon1 = new ol.geom.Polygon(
|
||||
[[[1000, 2000], [1200, 2000], [1200, 3000]]]
|
||||
);
|
||||
replay.drawPolygon(polygon1, null);
|
||||
expect(replay.vertices).to.have.length(8);
|
||||
expect(replay.indices).to.have.length(3);
|
||||
|
||||
expect(replay.vertices).to.eql([
|
||||
1000, 2000, 1200, 3000, 1200, 2000, 1000, 2000]);
|
||||
expect(replay.indices).to.eql([2, 0, 1]);
|
||||
|
||||
var polygon2 = new ol.geom.Polygon(
|
||||
[[[4000, 2000], [4200, 2000], [4200, 3000]]]
|
||||
);
|
||||
replay.drawPolygon(polygon2, null);
|
||||
expect(replay.vertices).to.have.length(16);
|
||||
expect(replay.indices).to.have.length(6);
|
||||
|
||||
expect(replay.vertices).to.eql([
|
||||
1000, 2000, 1200, 3000, 1200, 2000, 1000, 2000,
|
||||
4000, 2000, 4200, 3000, 4200, 2000, 4000, 2000
|
||||
]);
|
||||
expect(replay.indices).to.eql([2, 0, 1, 6, 4, 5]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#drawMultiPolygon', function() {
|
||||
beforeEach(function() {
|
||||
replay.setFillStrokeStyle(fillStyle, strokeStyle);
|
||||
});
|
||||
|
||||
it('sets the buffer data', function() {
|
||||
var multiPolygon = new ol.geom.MultiPolygon([
|
||||
[[[1000, 2000], [1200, 2000], [1200, 3000]]],
|
||||
[[[4000, 2000], [4200, 2000], [4200, 3000]]]
|
||||
]);
|
||||
replay.drawMultiPolygon(multiPolygon, null);
|
||||
expect(replay.vertices).to.have.length(16);
|
||||
expect(replay.indices).to.have.length(6);
|
||||
|
||||
expect(replay.vertices).to.eql([
|
||||
1000, 2000, 1200, 3000, 1200, 2000, 1000, 2000,
|
||||
4000, 2000, 4200, 3000, 4200, 2000, 4000, 2000
|
||||
]);
|
||||
expect(replay.indices).to.eql([2, 0, 1, 6, 4, 5]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('triangulating functions', function() {
|
||||
var list, rtree;
|
||||
beforeEach(function() {
|
||||
list = new ol.structs.LinkedList();
|
||||
rtree = new ol.structs.RBush();
|
||||
});
|
||||
|
||||
describe('#createPoint_', function() {
|
||||
it('creates a WebGL polygon vertex', function() {
|
||||
var p = replay.createPoint_(1, 1, 1);
|
||||
expect(p.x).to.be(1);
|
||||
expect(p.y).to.be(1);
|
||||
expect(p.i).to.be(1);
|
||||
expect(p.reflex).to.be(undefined);
|
||||
});
|
||||
|
||||
it('adds the point to the vertex array', function() {
|
||||
replay.createPoint_(1, 1, 1);
|
||||
expect(replay.vertices.length).to.be(2);
|
||||
expect(replay.vertices[0]).to.be(1);
|
||||
expect(replay.vertices[1]).to.be(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#insertItem_', function() {
|
||||
var p0, p1;
|
||||
beforeEach(function() {
|
||||
p0 = replay.createPoint_(1, 1, 1);
|
||||
p1 = replay.createPoint_(2, 2, 2);
|
||||
});
|
||||
|
||||
it('creates a WebGL polygon segment', function() {
|
||||
var seg = replay.insertItem_(p0, p1, list, rtree);
|
||||
expect(seg.p0).to.be(p0);
|
||||
expect(seg.p1).to.be(p1);
|
||||
});
|
||||
|
||||
it('inserts the segment into the provided linked list', function() {
|
||||
var seg = replay.insertItem_(p0, p1, list, rtree);
|
||||
expect(list.head_.data).to.be(seg);
|
||||
});
|
||||
|
||||
it('inserts the segment into the R-Tree, if provided', function() {
|
||||
replay.insertItem_(p0, p1, list);
|
||||
expect(rtree.isEmpty()).to.be(true);
|
||||
replay.insertItem_(p0, p1, list, rtree);
|
||||
expect(rtree.isEmpty()).to.be(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#removeItem_', function() {
|
||||
var s0, s1;
|
||||
beforeEach(function() {
|
||||
var p = replay.createPoint_(2, 2, 2);
|
||||
s0 = replay.insertItem_(replay.createPoint_(1, 1, 1),
|
||||
p, list, rtree);
|
||||
s1 = replay.insertItem_(p,
|
||||
replay.createPoint_(5, 2, 3), list, rtree);
|
||||
});
|
||||
|
||||
it('removes the current item', function() {
|
||||
replay.removeItem_(s0, s1, list, rtree);
|
||||
expect(list.head_.data).not.to.be(s1);
|
||||
expect(rtree.getAll().length).to.be(1);
|
||||
});
|
||||
|
||||
it('updates the preceding segment', function() {
|
||||
var dataExtent = rtree.getExtent();
|
||||
replay.removeItem_(s0, s1, list, rtree);
|
||||
expect(s0.p1).to.be(s1.p1);
|
||||
expect(rtree.getExtent()).to.eql(dataExtent);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#getPointsInTriangle_', function() {
|
||||
var p0, p1, p2, p3;
|
||||
beforeEach(function() {
|
||||
p0 = replay.createPoint_(2, 0, 0);
|
||||
p1 = replay.createPoint_(0, 5, 1);
|
||||
p2 = replay.createPoint_(2, 3, 2);
|
||||
p3 = replay.createPoint_(4, 5, 3);
|
||||
replay.insertItem_(p0, p1, list, rtree);
|
||||
replay.insertItem_(p1, p2, list, rtree);
|
||||
replay.insertItem_(p2, p3, list, rtree);
|
||||
replay.insertItem_(p3, p0, list, rtree);
|
||||
replay.classifyPoints_(list, rtree, false);
|
||||
});
|
||||
|
||||
it('gets every point in a triangle', function() {
|
||||
var points = replay.getPointsInTriangle_({x: -3, y: 6}, {x: 7, y: 6},
|
||||
{x: 2, y: 2}, rtree);
|
||||
expect(points).to.eql([p1, p2, p3]);
|
||||
});
|
||||
|
||||
it('gets only reflex points in a triangle', function() {
|
||||
var points = replay.getPointsInTriangle_({x: -3, y: 6}, {x: 7, y: 6},
|
||||
{x: 2, y: 2}, rtree, true);
|
||||
expect(points).to.eql([p2]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#getIntersections_', function() {
|
||||
var p0, p1, p2, p3, s0, s1, s2, s3;
|
||||
beforeEach(function() {
|
||||
p0 = replay.createPoint_(2, 0, 0);
|
||||
p1 = replay.createPoint_(0, 5, 1);
|
||||
p2 = replay.createPoint_(2, 3, 2);
|
||||
p3 = replay.createPoint_(4, 5, 3);
|
||||
s0 = replay.insertItem_(p0, p1, list, rtree);
|
||||
s1 = replay.insertItem_(p1, p2, list, rtree);
|
||||
s2 = replay.insertItem_(p2, p3, list, rtree);
|
||||
s3 = replay.insertItem_(p3, p0, list, rtree);
|
||||
});
|
||||
|
||||
it('gets intersecting, but non touching segments', function() {
|
||||
var segments = replay.getIntersections_({p0: {x: 0, y: 3}, p1: {x: 4, y: 5}},
|
||||
rtree);
|
||||
expect(segments).to.eql([s0, s1]);
|
||||
});
|
||||
|
||||
it('gets intersecting and touching segments', function() {
|
||||
var segments = replay.getIntersections_({p0: {x: 0, y: 3}, p1: {x: 4, y: 5}},
|
||||
rtree, true);
|
||||
expect(segments).to.eql([s0, s1, s2, s3]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#calculateIntersection_', function() {
|
||||
var p0 = {x: 0, y: 0};
|
||||
var p1 = {x: 4, y: 4};
|
||||
var p2 = {x: 0, y: 4};
|
||||
var p3 = {x: 4, y: 0};
|
||||
|
||||
it('calculates the intersection point of two intersecting segments', function() {
|
||||
var i = replay.calculateIntersection_(p0, p1, p2, p3);
|
||||
var t = replay.calculateIntersection_(p0, p1, p1, p2);
|
||||
expect(i).to.eql([2, 2]);
|
||||
expect(t).to.be(undefined);
|
||||
});
|
||||
|
||||
it('calculates the intersection point of two touching segments', function() {
|
||||
var t = replay.calculateIntersection_(p0, p1, p1, p2, true);
|
||||
expect(t).to.eql([4, 4]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#diagonalIsInside_', function() {
|
||||
var p0, p1, p2, p3;
|
||||
beforeEach(function() {
|
||||
p0 = replay.createPoint_(2, 0, 0);
|
||||
p1 = replay.createPoint_(0, 5, 1);
|
||||
p2 = replay.createPoint_(2, 3, 2);
|
||||
p3 = replay.createPoint_(4, 5, 3);
|
||||
replay.insertItem_(p0, p1, list, rtree);
|
||||
replay.insertItem_(p1, p2, list, rtree);
|
||||
replay.insertItem_(p2, p3, list, rtree);
|
||||
replay.insertItem_(p3, p0, list, rtree);
|
||||
replay.classifyPoints_(list, rtree, false);
|
||||
});
|
||||
|
||||
it('identifies if diagonal is inside the polygon', function() {
|
||||
var inside = replay.diagonalIsInside_(p1, p2, p3, p0, p1);
|
||||
expect(inside).to.be(true);
|
||||
});
|
||||
|
||||
it('identifies if diagonal is outside the polygon', function() {
|
||||
var inside = replay.diagonalIsInside_(p0, p1, p2, p3, p0);
|
||||
expect(inside).to.be(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#classifyPoints_', function() {
|
||||
var p0, p1, p2, p3;
|
||||
beforeEach(function() {
|
||||
p0 = replay.createPoint_(2, 0, 0);
|
||||
p1 = replay.createPoint_(0, 5, 1);
|
||||
p2 = replay.createPoint_(2, 3, 2);
|
||||
p3 = replay.createPoint_(4, 5, 3);
|
||||
replay.insertItem_(p0, p1, list, rtree);
|
||||
replay.insertItem_(p1, p2, list, rtree);
|
||||
replay.insertItem_(p2, p3, list, rtree);
|
||||
replay.insertItem_(p3, p0, list, rtree);
|
||||
});
|
||||
|
||||
it('classifies the points of clockwise polygons', function() {
|
||||
replay.classifyPoints_(list, rtree, false);
|
||||
expect(p0.reflex).to.be(false);
|
||||
expect(p1.reflex).to.be(false);
|
||||
expect(p2.reflex).to.be(true);
|
||||
expect(p3.reflex).to.be(false);
|
||||
});
|
||||
|
||||
it('classifies the points of counter-clockwise polygons', function() {
|
||||
replay.classifyPoints_(list, rtree, true);
|
||||
expect(p0.reflex).to.be(true);
|
||||
expect(p1.reflex).to.be(true);
|
||||
expect(p2.reflex).to.be(false);
|
||||
expect(p3.reflex).to.be(true);
|
||||
});
|
||||
|
||||
it('removes collinear points', function() {
|
||||
replay.insertItem_(p3, p0, list, rtree);
|
||||
replay.classifyPoints_(list, rtree, false);
|
||||
expect(list.getLength()).to.be(4);
|
||||
expect(rtree.getAll().length).to.be(4);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#isSimple_', function() {
|
||||
var p0, p1, p2, p3;
|
||||
beforeEach(function() {
|
||||
p0 = replay.createPoint_(2, 0, 0);
|
||||
p1 = replay.createPoint_(0, 5, 1);
|
||||
p2 = replay.createPoint_(2, 3, 2);
|
||||
p3 = replay.createPoint_(4, 5, 3);
|
||||
replay.insertItem_(p0, p1, list, rtree);
|
||||
replay.insertItem_(p1, p2, list, rtree);
|
||||
replay.insertItem_(p2, p3, list, rtree);
|
||||
replay.insertItem_(p3, p0, list, rtree);
|
||||
});
|
||||
|
||||
it('identifies simple polygons', function() {
|
||||
var simple = replay.isSimple_(list, rtree);
|
||||
expect(simple).to.be(true);
|
||||
});
|
||||
|
||||
it('identifies self-intersecting polygons', function() {
|
||||
var p4 = replay.createPoint_(2, 5, 4);
|
||||
var p5 = replay.createPoint_(4, 2, 5);
|
||||
replay.insertItem_(p0, p4, list, rtree);
|
||||
replay.insertItem_(p4, p5, list, rtree);
|
||||
replay.insertItem_(p5, p0, list, rtree);
|
||||
var simple = replay.isSimple_(list, rtree);
|
||||
expect(simple).to.be(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('#setUpProgram', function() {
|
||||
var context, gl;
|
||||
beforeEach(function() {
|
||||
context = {
|
||||
getProgram: function() {},
|
||||
useProgram: function() {}
|
||||
};
|
||||
gl = {
|
||||
enableVertexAttribArray: function() {},
|
||||
vertexAttribPointer: function() {},
|
||||
uniform1f: function() {},
|
||||
uniform2fv: function() {},
|
||||
getUniformLocation: function() {},
|
||||
getAttribLocation: function() {}
|
||||
};
|
||||
});
|
||||
|
||||
it('returns the locations used by the shaders', function() {
|
||||
var locations = replay.setUpProgram(gl, context, [2, 2], 1);
|
||||
expect(locations).to.be.a(
|
||||
ol.render.webgl.polygonreplay.defaultshader.Locations);
|
||||
});
|
||||
|
||||
it('gets and compiles the shaders', function() {
|
||||
sinon.spy(context, 'getProgram');
|
||||
sinon.spy(context, 'useProgram');
|
||||
|
||||
replay.setUpProgram(gl, context, [2, 2], 1);
|
||||
expect(context.getProgram.calledWithExactly(
|
||||
ol.render.webgl.polygonreplay.defaultshader.fragment,
|
||||
ol.render.webgl.polygonreplay.defaultshader.vertex)).to.be(true);
|
||||
expect(context.useProgram.calledOnce).to.be(true);
|
||||
});
|
||||
|
||||
it('initializes the attrib pointers', function() {
|
||||
sinon.spy(gl, 'getAttribLocation');
|
||||
sinon.spy(gl, 'vertexAttribPointer');
|
||||
sinon.spy(gl, 'enableVertexAttribArray');
|
||||
|
||||
replay.setUpProgram(gl, context, [2, 2], 1);
|
||||
expect(gl.vertexAttribPointer.callCount).to.be(gl.getAttribLocation.callCount);
|
||||
expect(gl.enableVertexAttribArray.callCount).to.be(
|
||||
gl.getAttribLocation.callCount);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#shutDownProgram', function() {
|
||||
var context, gl;
|
||||
beforeEach(function() {
|
||||
context = {
|
||||
getProgram: function() {},
|
||||
useProgram: function() {}
|
||||
};
|
||||
gl = {
|
||||
enableVertexAttribArray: function() {},
|
||||
disableVertexAttribArray: function() {},
|
||||
vertexAttribPointer: function() {},
|
||||
uniform1f: function() {},
|
||||
uniform2fv: function() {},
|
||||
getUniformLocation: function() {},
|
||||
getAttribLocation: function() {}
|
||||
};
|
||||
});
|
||||
|
||||
it('disables the attrib pointers', function() {
|
||||
sinon.spy(gl, 'getAttribLocation');
|
||||
sinon.spy(gl, 'disableVertexAttribArray');
|
||||
|
||||
var locations = replay.setUpProgram(gl, context, [2, 2], 1);
|
||||
replay.shutDownProgram(gl, locations);
|
||||
expect(gl.disableVertexAttribArray.callCount).to.be(
|
||||
gl.getAttribLocation.callCount);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#drawReplay', function() {
|
||||
var gl, context;
|
||||
var feature1 = new ol.Feature({
|
||||
geometry: new ol.geom.Polygon([[[0, 0], [500, 500], [500, 0], [0, 0]]])
|
||||
});
|
||||
var feature2 = new ol.Feature({
|
||||
geometry: new ol.geom.Polygon([[[0, 0], [500, 500], [500, 0], [0, 0]]])
|
||||
});
|
||||
var feature3 = new ol.Feature({
|
||||
geometry: new ol.geom.Polygon([[[0, 0], [500, 500], [500, 0], [0, 0]]])
|
||||
});
|
||||
beforeEach(function() {
|
||||
gl = {
|
||||
getParameter: function() {},
|
||||
enable: function() {},
|
||||
disable: function() {},
|
||||
depthMask: function() {},
|
||||
depthFunc: function() {},
|
||||
clear: function() {}
|
||||
};
|
||||
context = {};
|
||||
replay.setFillStyle_ = function() {};
|
||||
replay.drawElements = function() {};
|
||||
sinon.spy(replay, 'setFillStyle_');
|
||||
sinon.spy(replay, 'drawElements');
|
||||
});
|
||||
|
||||
it('draws the elements in a single call if they have the same style', function() {
|
||||
replay.setFillStrokeStyle(fillStyle, strokeStyle);
|
||||
replay.drawPolygon(feature1.getGeometry(), feature1);
|
||||
replay.setFillStrokeStyle(fillStyle, strokeStyle);
|
||||
replay.drawPolygon(feature2.getGeometry(), feature2);
|
||||
replay.setFillStrokeStyle(fillStyle, strokeStyle);
|
||||
replay.drawPolygon(feature3.getGeometry(), feature3);
|
||||
replay.startIndices.push(replay.indices.length);
|
||||
|
||||
replay.drawReplay(gl, context, {}, false);
|
||||
expect(replay.setFillStyle_.calledOnce).to.be(true);
|
||||
expect(replay.drawElements.calledOnce).to.be(true);
|
||||
});
|
||||
|
||||
it('draws the elements in batches if there are multiple fill styles', function() {
|
||||
var fillStyle2 = new ol.style.Fill({
|
||||
color: [0, 255, 0, 1]
|
||||
});
|
||||
replay.setFillStrokeStyle(fillStyle, strokeStyle);
|
||||
replay.drawPolygon(feature1.getGeometry(), feature1);
|
||||
replay.setFillStrokeStyle(fillStyle2, strokeStyle);
|
||||
replay.drawPolygon(feature2.getGeometry(), feature2);
|
||||
replay.setFillStrokeStyle(fillStyle, strokeStyle);
|
||||
replay.drawPolygon(feature3.getGeometry(), feature3);
|
||||
replay.startIndices.push(replay.indices.length);
|
||||
|
||||
replay.drawReplay(gl, context, {}, false);
|
||||
expect(replay.setFillStyle_.calledThrice).to.be(true);
|
||||
expect(replay.drawElements.calledThrice).to.be(true);
|
||||
});
|
||||
|
||||
it('can skip elements if needed', function() {
|
||||
replay.setFillStrokeStyle(fillStyle, strokeStyle);
|
||||
replay.drawPolygon(feature1.getGeometry(), feature1);
|
||||
replay.setFillStrokeStyle(fillStyle, strokeStyle);
|
||||
replay.drawPolygon(feature2.getGeometry(), feature2);
|
||||
replay.setFillStrokeStyle(fillStyle, strokeStyle);
|
||||
replay.drawPolygon(feature3.getGeometry(), feature3);
|
||||
replay.startIndices.push(replay.indices.length);
|
||||
var skippedFeatHash = {};
|
||||
skippedFeatHash[ol.getUid(feature2).toString()] = true;
|
||||
|
||||
replay.drawReplay(gl, context, skippedFeatHash, false);
|
||||
expect(replay.setFillStyle_.calledOnce).to.be(true);
|
||||
expect(replay.drawElements.calledTwice).to.be(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,170 +0,0 @@
|
||||
goog.provide('ol.test.render.webgl.Replay');
|
||||
|
||||
goog.require('ol.geom.MultiPoint');
|
||||
goog.require('ol.geom.Point');
|
||||
goog.require('ol.render.webgl.ImageReplay');
|
||||
goog.require('ol.style.Image');
|
||||
|
||||
|
||||
describe('ol.render.webgl.ImageReplay', function() {
|
||||
var replay;
|
||||
|
||||
var createImageStyle = function(image) {
|
||||
var imageStyle = new ol.style.Image({
|
||||
opacity: 0.1,
|
||||
rotateWithView: true,
|
||||
rotation: 1.5,
|
||||
scale: 2.0
|
||||
});
|
||||
imageStyle.getAnchor = function() {
|
||||
return [0.5, 1];
|
||||
};
|
||||
imageStyle.getImage = function() {
|
||||
return image;
|
||||
};
|
||||
imageStyle.getHitDetectionImage = function() {
|
||||
return image;
|
||||
};
|
||||
imageStyle.getImageSize = function() {
|
||||
return [512, 512];
|
||||
};
|
||||
imageStyle.getHitDetectionImageSize = function() {
|
||||
return [512, 512];
|
||||
};
|
||||
imageStyle.getOrigin = function() {
|
||||
return [200, 200];
|
||||
};
|
||||
imageStyle.getSize = function() {
|
||||
return [256, 256];
|
||||
};
|
||||
return imageStyle;
|
||||
};
|
||||
|
||||
beforeEach(function() {
|
||||
var tolerance = 0.1;
|
||||
var maxExtent = [-10000, -20000, 10000, 20000];
|
||||
replay = new ol.render.webgl.ImageReplay(tolerance, maxExtent);
|
||||
});
|
||||
|
||||
describe('#setImageStyle', function() {
|
||||
|
||||
var imageStyle1, imageStyle2;
|
||||
|
||||
beforeEach(function() {
|
||||
imageStyle1 = createImageStyle(new Image());
|
||||
imageStyle2 = createImageStyle(new Image());
|
||||
});
|
||||
|
||||
it('set expected states', function() {
|
||||
replay.setImageStyle(imageStyle1);
|
||||
expect(replay.anchorX_).to.be(0.5);
|
||||
expect(replay.anchorY_).to.be(1);
|
||||
expect(replay.height_).to.be(256);
|
||||
expect(replay.imageHeight_).to.be(512);
|
||||
expect(replay.imageWidth_).to.be(512);
|
||||
expect(replay.opacity_).to.be(0.1);
|
||||
expect(replay.originX_).to.be(200);
|
||||
expect(replay.originY_).to.be(200);
|
||||
expect(replay.rotation_).to.be(1.5);
|
||||
expect(replay.rotateWithView_).to.be(true);
|
||||
expect(replay.scale_).to.be(2.0);
|
||||
expect(replay.width_).to.be(256);
|
||||
expect(replay.images_).to.have.length(1);
|
||||
expect(replay.groupIndices_).to.have.length(0);
|
||||
expect(replay.hitDetectionImages_).to.have.length(1);
|
||||
expect(replay.hitDetectionGroupIndices_).to.have.length(0);
|
||||
|
||||
replay.setImageStyle(imageStyle1);
|
||||
expect(replay.images_).to.have.length(1);
|
||||
expect(replay.groupIndices_).to.have.length(0);
|
||||
expect(replay.hitDetectionImages_).to.have.length(1);
|
||||
expect(replay.hitDetectionGroupIndices_).to.have.length(0);
|
||||
|
||||
replay.setImageStyle(imageStyle2);
|
||||
expect(replay.images_).to.have.length(2);
|
||||
expect(replay.groupIndices_).to.have.length(1);
|
||||
expect(replay.hitDetectionImages_).to.have.length(2);
|
||||
expect(replay.hitDetectionGroupIndices_).to.have.length(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#drawPoint', function() {
|
||||
beforeEach(function() {
|
||||
var imageStyle = createImageStyle(new Image());
|
||||
replay.setImageStyle(imageStyle);
|
||||
});
|
||||
|
||||
it('sets the buffer data', function() {
|
||||
var point;
|
||||
|
||||
point = new ol.geom.Point([1000, 2000]);
|
||||
replay.drawPoint(point, null);
|
||||
expect(replay.vertices_).to.have.length(32);
|
||||
expect(replay.indices_).to.have.length(6);
|
||||
expect(replay.indices_[0]).to.be(0);
|
||||
expect(replay.indices_[1]).to.be(1);
|
||||
expect(replay.indices_[2]).to.be(2);
|
||||
expect(replay.indices_[3]).to.be(0);
|
||||
expect(replay.indices_[4]).to.be(2);
|
||||
expect(replay.indices_[5]).to.be(3);
|
||||
|
||||
point = new ol.geom.Point([2000, 3000]);
|
||||
replay.drawPoint(point, null);
|
||||
expect(replay.vertices_).to.have.length(64);
|
||||
expect(replay.indices_).to.have.length(12);
|
||||
expect(replay.indices_[6]).to.be(4);
|
||||
expect(replay.indices_[7]).to.be(5);
|
||||
expect(replay.indices_[8]).to.be(6);
|
||||
expect(replay.indices_[9]).to.be(4);
|
||||
expect(replay.indices_[10]).to.be(6);
|
||||
expect(replay.indices_[11]).to.be(7);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#drawMultiPoint', function() {
|
||||
beforeEach(function() {
|
||||
var imageStyle = createImageStyle(new Image());
|
||||
replay.setImageStyle(imageStyle);
|
||||
});
|
||||
|
||||
it('sets the buffer data', function() {
|
||||
var multiPoint;
|
||||
|
||||
multiPoint = new ol.geom.MultiPoint(
|
||||
[[1000, 2000], [2000, 3000]]);
|
||||
replay.drawMultiPoint(multiPoint, null);
|
||||
expect(replay.vertices_).to.have.length(64);
|
||||
expect(replay.indices_).to.have.length(12);
|
||||
expect(replay.indices_[0]).to.be(0);
|
||||
expect(replay.indices_[1]).to.be(1);
|
||||
expect(replay.indices_[2]).to.be(2);
|
||||
expect(replay.indices_[3]).to.be(0);
|
||||
expect(replay.indices_[4]).to.be(2);
|
||||
expect(replay.indices_[5]).to.be(3);
|
||||
expect(replay.indices_[6]).to.be(4);
|
||||
expect(replay.indices_[7]).to.be(5);
|
||||
expect(replay.indices_[8]).to.be(6);
|
||||
expect(replay.indices_[9]).to.be(4);
|
||||
expect(replay.indices_[10]).to.be(6);
|
||||
expect(replay.indices_[11]).to.be(7);
|
||||
|
||||
multiPoint = new ol.geom.MultiPoint(
|
||||
[[3000, 4000], [4000, 5000]]);
|
||||
replay.drawMultiPoint(multiPoint, null);
|
||||
expect(replay.vertices_).to.have.length(128);
|
||||
expect(replay.indices_).to.have.length(24);
|
||||
expect(replay.indices_[12]).to.be(8);
|
||||
expect(replay.indices_[13]).to.be(9);
|
||||
expect(replay.indices_[14]).to.be(10);
|
||||
expect(replay.indices_[15]).to.be(8);
|
||||
expect(replay.indices_[16]).to.be(10);
|
||||
expect(replay.indices_[17]).to.be(11);
|
||||
expect(replay.indices_[18]).to.be(12);
|
||||
expect(replay.indices_[19]).to.be(13);
|
||||
expect(replay.indices_[20]).to.be(14);
|
||||
expect(replay.indices_[21]).to.be(12);
|
||||
expect(replay.indices_[22]).to.be(14);
|
||||
expect(replay.indices_[23]).to.be(15);
|
||||
});
|
||||
});
|
||||
});
|
||||
267
test/spec/ol/structs/linkedlist.test.js
Normal file
267
test/spec/ol/structs/linkedlist.test.js
Normal file
@@ -0,0 +1,267 @@
|
||||
goog.provide('ol.test.structs.LinkedList');
|
||||
|
||||
goog.require('ol.structs.LinkedList');
|
||||
|
||||
describe('ol.structs.LinkedList', function() {
|
||||
var ll;
|
||||
var item = {};
|
||||
var item2 = {};
|
||||
beforeEach(function() {
|
||||
ll = new ol.structs.LinkedList();
|
||||
});
|
||||
|
||||
it('defaults to circular', function() {
|
||||
expect(ll.circular_).to.be(true);
|
||||
});
|
||||
|
||||
it('creates an empty list', function() {
|
||||
expect(ll.length_).to.be(0);
|
||||
expect(ll.first_).to.be(undefined);
|
||||
expect(ll.last_).to.be(undefined);
|
||||
expect(ll.head_).to.be(undefined);
|
||||
});
|
||||
|
||||
describe('#insertItem', function() {
|
||||
beforeEach(function() {
|
||||
ll.insertItem(item);
|
||||
});
|
||||
|
||||
it('inserts an item into the list', function() {
|
||||
expect(ll.length_).to.be(1);
|
||||
});
|
||||
|
||||
it('sets the cursor to the inserted item', function() {
|
||||
expect(ll.head_.data).to.be(item);
|
||||
});
|
||||
|
||||
it('links the previous item to the new one', function() {
|
||||
ll.insertItem(item2);
|
||||
expect(ll.head_.prev.data).to.be(item);
|
||||
expect(ll.head_.prev.next.data).to.be(item2);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#removeItem', function() {
|
||||
var item3 = {};
|
||||
beforeEach(function() {
|
||||
ll.insertItem(item);
|
||||
ll.insertItem(item2);
|
||||
ll.insertItem(item3);
|
||||
});
|
||||
|
||||
it('removes the current item', function() {
|
||||
ll.removeItem();
|
||||
expect(ll.length_).to.be(2);
|
||||
expect(ll.head_.data).not.to.be(item3);
|
||||
});
|
||||
|
||||
it('sets the cursor to the next item if possible', function() {
|
||||
ll.removeItem();
|
||||
expect(ll.head_.data).to.be(item);
|
||||
});
|
||||
|
||||
it('otherwise sets the cursor to the prevous item', function() {
|
||||
ll = new ol.structs.LinkedList(false);
|
||||
ll.insertItem(item);
|
||||
ll.insertItem(item2);
|
||||
ll.insertItem(item3);
|
||||
ll.removeItem();
|
||||
expect(ll.head_.data).to.be(item2);
|
||||
});
|
||||
|
||||
it('empties a list with only one item', function() {
|
||||
ll = new ol.structs.LinkedList();
|
||||
ll.insertItem(item);
|
||||
ll.removeItem();
|
||||
expect(ll.length_).to.be(0);
|
||||
expect(ll.head_).to.be(undefined);
|
||||
expect(ll.first_).to.be(undefined);
|
||||
expect(ll.last_).to.be(undefined);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#firstItem', function() {
|
||||
it('sets the cursor to the first item and returns its data', function() {
|
||||
ll.insertItem(item);
|
||||
ll.insertItem(item2);
|
||||
var i = ll.firstItem();
|
||||
expect(i).to.be(item);
|
||||
expect(ll.head_.data).to.be(item);
|
||||
});
|
||||
|
||||
it('returns undefined on empty list', function() {
|
||||
var i = ll.firstItem();
|
||||
expect(i).to.be(undefined);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#lastItem', function() {
|
||||
it('sets the cursor to the last item and returns its data', function() {
|
||||
ll.insertItem(item);
|
||||
ll.insertItem(item2);
|
||||
ll.firstItem();
|
||||
var i = ll.lastItem();
|
||||
expect(i).to.be(item2);
|
||||
expect(ll.head_.data).to.be(item2);
|
||||
});
|
||||
|
||||
it('returns undefined on empty list', function() {
|
||||
var i = ll.lastItem();
|
||||
expect(i).to.be(undefined);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#nextItem', function() {
|
||||
it('sets the cursor to the next item and returns its data', function() {
|
||||
ll.insertItem(item);
|
||||
ll.insertItem(item2);
|
||||
ll.firstItem();
|
||||
var i = ll.nextItem();
|
||||
expect(i).to.be(item2);
|
||||
expect(ll.head_.data).to.be(item2);
|
||||
});
|
||||
|
||||
it('returns undefined on empty list', function() {
|
||||
var i = ll.nextItem();
|
||||
expect(i).to.be(undefined);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#prevItem', function() {
|
||||
it('sets the cursor to the previous item and returns its data', function() {
|
||||
ll.insertItem(item);
|
||||
ll.insertItem(item2);
|
||||
var i = ll.prevItem();
|
||||
expect(i).to.be(item);
|
||||
expect(ll.head_.data).to.be(item);
|
||||
});
|
||||
|
||||
it('returns undefined on empty list', function() {
|
||||
var i = ll.prevItem();
|
||||
expect(i).to.be(undefined);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#getNextItem', function() {
|
||||
it('returns the data of the next item without stepping the cursor', function() {
|
||||
ll.insertItem(item);
|
||||
ll.insertItem(item2);
|
||||
ll.firstItem();
|
||||
var i = ll.getNextItem();
|
||||
expect(i).to.be(item2);
|
||||
expect(ll.head_.data).to.be(item);
|
||||
});
|
||||
|
||||
it('returns undefined on empty list', function() {
|
||||
var i = ll.getNextItem();
|
||||
expect(i).to.be(undefined);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#getPrevItem', function() {
|
||||
it('returns the data of the previous item without stepping the cursor', function() {
|
||||
ll.insertItem(item);
|
||||
ll.insertItem(item2);
|
||||
var i = ll.getPrevItem();
|
||||
expect(i).to.be(item);
|
||||
expect(ll.head_.data).to.be(item2);
|
||||
});
|
||||
|
||||
it('returns undefined on empty list', function() {
|
||||
var i = ll.getPrevItem();
|
||||
expect(i).to.be(undefined);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#getCurrItem', function() {
|
||||
it('returns the data of the current item', function() {
|
||||
var item3 = {};
|
||||
ll.insertItem(item);
|
||||
ll.insertItem(item2);
|
||||
ll.insertItem(item3);
|
||||
ll.prevItem();
|
||||
var i = ll.getCurrItem();
|
||||
expect(i).to.be(item2);
|
||||
expect(ll.head_.data).to.be(item2);
|
||||
});
|
||||
|
||||
it('returns undefined on empty list', function() {
|
||||
var i = ll.getCurrItem();
|
||||
expect(i).to.be(undefined);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#getLength', function() {
|
||||
it('returns the length of the list', function() {
|
||||
ll.insertItem(item);
|
||||
ll.insertItem(item2);
|
||||
var l = ll.getLength();
|
||||
expect(l).to.be(2);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#concat', function() {
|
||||
var ll2, item3;
|
||||
beforeEach(function() {
|
||||
item3 = {};
|
||||
ll2 = new ol.structs.LinkedList();
|
||||
ll2.insertItem(item);
|
||||
ll2.insertItem(item2);
|
||||
ll2.insertItem(item3);
|
||||
});
|
||||
|
||||
it('concatenates a second list with the current one', function() {
|
||||
var item4 = {};
|
||||
var item5 = {};
|
||||
var item6 = {};
|
||||
ll.insertItem(item4);
|
||||
ll.insertItem(item5);
|
||||
ll.insertItem(item6);
|
||||
ll.prevItem();
|
||||
ll.concat(ll2);
|
||||
expect(ll.length_).to.be(6);
|
||||
expect(ll.head_.data).to.be(item5);
|
||||
expect(ll.head_.next.data).to.be(item);
|
||||
expect(ll.head_.next.next.next.next.data).to.be(item6);
|
||||
});
|
||||
|
||||
it('receives the second list if the current one is empty', function() {
|
||||
ll.concat(ll2);
|
||||
expect(ll.length_).to.be(3);
|
||||
expect(ll.first_.data).to.be(item);
|
||||
expect(ll.last_.data).to.be(item3);
|
||||
expect(ll.head_.data).to.be(item3);
|
||||
});
|
||||
|
||||
it('destroys the second list', function() {
|
||||
ll.concat(ll2);
|
||||
expect(ll2.length_).to.be(0);
|
||||
expect(ll2.first_).to.be(undefined);
|
||||
expect(ll2.last_).to.be(undefined);
|
||||
expect(ll2.head_).to.be(undefined);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when circular', function() {
|
||||
beforeEach(function() {
|
||||
ll = new ol.structs.LinkedList();
|
||||
ll.insertItem(item);
|
||||
});
|
||||
|
||||
describe('#insertItem', function() {
|
||||
it('initializes the list in a circular way', function() {
|
||||
expect(ll.head_.prev.data).to.be(item);
|
||||
expect(ll.head_.next.data).to.be(item);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#setFirstItem', function() {
|
||||
it('resets the first item to the current one', function() {
|
||||
ll.insertItem(item2);
|
||||
ll.setFirstItem();
|
||||
expect(ll.first_.data).to.be(item2);
|
||||
expect(ll.last_.data).to.be(item);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user