From 8e0c21eb580bbd7a659fa5088b9c145030f9b872 Mon Sep 17 00:00:00 2001 From: tsauerwein Date: Thu, 2 Apr 2015 12:11:03 +0200 Subject: [PATCH 1/3] Add test-suite using SlimerJS --- .travis.yml | 4 + build.py | 57 ++++++++--- package.json | 4 +- tasks/serve.js | 26 ++++-- tasks/test-coverage.js | 2 +- tasks/test-rendering.js | 65 +++++++++++++ tasks/test.js | 5 +- test/test-extensions.js | 104 ++++++++++++++++++++- test_rendering/README.md | 24 +++++ test_rendering/index.html | 93 ++++++++++++++++++ test_rendering/slimerjs-profile/prefs.js | 3 + test_rendering/slimerjs-profile/times.json | 3 + test_rendering/test.js | 30 ++++++ 13 files changed, 394 insertions(+), 26 deletions(-) create mode 100644 tasks/test-rendering.js create mode 100644 test_rendering/README.md create mode 100644 test_rendering/index.html create mode 100644 test_rendering/slimerjs-profile/prefs.js create mode 100755 test_rendering/slimerjs-profile/times.json create mode 100644 test_rendering/test.js diff --git a/.travis.yml b/.travis.yml index 2d6908b488..cf56d6cc8d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,9 +1,13 @@ +env: + - DISPLAY=:99.0 + before_install: - "sudo pip install -r requirements.txt" - "npm install -g npm && npm install" before_script: - "rm src/ol/renderer/webgl/*shader.js" + - "sh -e /etc/init.d/xvfb start" script: "./build.py ci" diff --git a/build.py b/build.py index 615c5fb183..c27aec4304 100755 --- a/build.py +++ b/build.py @@ -145,6 +145,10 @@ SPEC = [path for path in ifind('test/spec') if path.endswith('.js')] +SPEC_RENDERING = [path + for path in ifind('test_rendering/spec') + if path.endswith('.js')] + TASKS = [path for path in ifind('tasks') if path.endswith('.js')] @@ -172,7 +176,7 @@ def report_sizes(t): virtual('default', 'build') -virtual('ci', 'lint', 'build', 'test', +virtual('ci', 'lint', 'build', 'test', 'test-rendering', 'build/examples/all.combined.js', 'check-examples', 'apidoc') @@ -231,19 +235,28 @@ for glsl_src in GLSL_SRC: shader_src_helper(glsl_src) -@target('build/test/requireall.js', SPEC) -def build_test_requireall_js(t): +def build_requires(task): requires = set() - for dependency in t.dependencies: + for dependency in task.dependencies: for line in open(dependency, 'rU'): match = re.match(r'goog\.provide\(\'(.*)\'\);', line) if match: requires.add(match.group(1)) - with open(t.name, 'wb') as f: + with open(task.name, 'wb') as f: for require in sorted(requires): f.write('goog.require(\'%s\');\n' % (require,)) +@target('build/test_requires.js', SPEC) +def build_test_requires(t): + build_requires(t) + + +@target('build/test_rendering_requires.js', SPEC_RENDERING) +def build_test_rendering_requires(t): + build_requires(t) + + virtual('build-examples', 'examples', 'build/examples/all.combined.js', EXAMPLES_COMBINED) @@ -389,7 +402,8 @@ def examples_star_combined_js(name, match): return Target(name, action=action, dependencies=dependencies) -@target('serve', 'examples', NPM_INSTALL) +@target('serve', 'examples', 'build/test_requires.js', 'build/test_rendering_requires.js', + NPM_INSTALL) def serve(t): t.run('node', 'tasks/serve.js') @@ -398,7 +412,8 @@ virtual('lint', 'build/lint-timestamp', 'build/check-requires-timestamp', 'build/check-whitespace-timestamp', 'jshint') -@target('build/lint-timestamp', SRC, EXAMPLES_SRC, SPEC, precious=True) +@target('build/lint-timestamp', SRC, EXAMPLES_SRC, SPEC, SPEC_RENDERING, + precious=True) def build_lint_src_timestamp(t): t.run('%(GJSLINT)s', '--jslint_error=all', @@ -409,8 +424,8 @@ def build_lint_src_timestamp(t): virtual('jshint', 'build/jshint-timestamp') -@target('build/jshint-timestamp', SRC, EXAMPLES_SRC, SPEC, TASKS, - NPM_INSTALL, precious=True) +@target('build/jshint-timestamp', SRC, EXAMPLES_SRC, SPEC, SPEC_RENDERING, + TASKS, NPM_INSTALL, precious=True) def build_jshint_timestamp(t): t.run(variables.JSHINT, '--verbose', t.newer(t.dependencies)) t.touch() @@ -439,7 +454,8 @@ def _strip_comments(lines): yield lineno, line -@target('build/check-requires-timestamp', SRC, EXAMPLES_SRC, SHADER_SRC, SPEC) +@target('build/check-requires-timestamp', SRC, EXAMPLES_SRC, SHADER_SRC, + SPEC, SPEC_RENDERING) def build_check_requires_timestamp(t): unused_count = 0 all_provides = set() @@ -580,7 +596,7 @@ def build_check_requires_timestamp(t): @target('build/check-whitespace-timestamp', SRC, EXAMPLES_SRC, - SPEC, JSDOC_SRC, precious=True) + SPEC, SPEC_RENDERING, JSDOC_SRC, precious=True) def build_check_whitespace_timestamp(t): CR_RE = re.compile(r'\r') LEADING_WHITESPACE_RE = re.compile(r'\s+') @@ -720,7 +736,7 @@ def check_examples(t): sys.exit(1) -@target('test', NPM_INSTALL, phony=True) +@target('test', NPM_INSTALL, 'build/test_requires.js', phony=True) def test(t): t.run('node', 'tasks/test.js') @@ -730,6 +746,16 @@ def test_coverage(t): t.run('node', 'tasks/test-coverage.js') +@target('test-rendering', 'build/test_rendering_requires.js', + NPM_INSTALL, phony=True) +def test_rendering(t): + # create a temp. profile to run the tests with WebGL + tmp_profile_dir = 'build/slimerjs-profile' + t.rm_rf(tmp_profile_dir) + t.cp_r('test_rendering/slimerjs-profile', tmp_profile_dir) + t.run('node', 'tasks/test-rendering.js') + + @target('fixme', phony=True) def find_fixme(t): regex = re.compile('FIXME|TODO') @@ -794,6 +820,7 @@ The most common targets are: CSS. This is also the default build target which runs when no target is specified. test - Runs the testsuite and displays the results. + test-rendering - Runs the rendering testsuite and displays the results. check - Runs the lint-target, builds some OpenLayers files, and then runs test. Many developers call this target often while working on the code. @@ -803,9 +830,9 @@ Other less frequently used targets are: apidoc - Builds the API-Documentation using JSDoc3. ci - Builds all examples in various modes and usually takes a long time to finish. This target calls the following - targets: lint, build, build-all, test, build-examples, - check-examples and apidoc. This is the target run on - Travis CI. + targets: lint, build, build-all, test, test-rendering, + build-examples, check-examples and apidoc. This is the + target run on Travis CI. test-coverage - Generates a test coverage report in the coverage folder. reallyclean - Remove untracked files from the repository. checkdeps - Checks whether all required development software is diff --git a/package.json b/package.json index b3ad9bb5b2..7e6510ad4a 100644 --- a/package.json +++ b/package.json @@ -53,7 +53,9 @@ "mocha-phantomjs": "3.5.1", "phantomjs": "1.9.10", "proj4": "2.3.3", - "sinon": "1.10.3" + "sinon": "1.10.3", + "slimerjs-edge": "0.10.0-pre-2", + "resemblejs": "1.2.0" }, "ext": [ "rbush" diff --git a/tasks/serve.js b/tasks/serve.js index a7f792d51b..dfed1e5e8d 100644 --- a/tasks/serve.js +++ b/tasks/serve.js @@ -23,7 +23,10 @@ var createServer = exports.createServer = function(callback) { lib: [ 'src/**/*.js', 'build/ol.ext/*.js', - 'test/spec/**/*.test.js' + 'test/spec/**/*.test.js', + 'test_rendering/spec/**/*.test.js', + 'build/test_requires.js', + 'build/test_rendering_requires.js' ], main: 'examples/*.js' }); @@ -41,12 +44,21 @@ var createServer = exports.createServer = function(callback) { getMain: function(req) { var main; var query = url.parse(req.url, true).query; - if (query.id) { - var referer = req.headers.referer; - if (referer) { - var from = path.join(process.cwd(), - path.dirname(url.parse(referer).pathname)); - main = path.resolve(from, query.id + '.js'); + var referer = req.headers.referer; + var pathName = url.parse(referer).pathname; + if (pathName.indexOf('/test/') === 0) { + main = path.resolve( + path.join(process.cwd(), 'build'), 'test_requires.js'); + } else if (pathName.indexOf('/test_rendering/') === 0) { + main = path.resolve( + path.join(process.cwd(), 'build'), 'test_rendering_requires.js'); + } else { + if (query.id) { + if (referer) { + var from = path.join(process.cwd(), + path.dirname(url.parse(referer).pathname)); + main = path.resolve(from, query.id + '.js'); + } } } return main; diff --git a/tasks/test-coverage.js b/tasks/test-coverage.js index 5e1aab20be..8fc0061e43 100644 --- a/tasks/test-coverage.js +++ b/tasks/test-coverage.js @@ -13,7 +13,7 @@ var wrench = require('wrench'); var path = require('path'); var glob = require('glob'); -var runTestsuite = require('./test'); +var runTestsuite = require('./test').runTests; // setup some pathes var dir = path.join(__dirname, '../src'); diff --git a/tasks/test-rendering.js b/tasks/test-rendering.js new file mode 100644 index 0000000000..d440a52e52 --- /dev/null +++ b/tasks/test-rendering.js @@ -0,0 +1,65 @@ +/** + * This task starts a dev server that provides a script loader for OpenLayers + * and Closure Library and runs rendering tests in SlimerJS. + */ + +var fs = require('fs'); +var path = require('path'); +var spawn = require('child_process').spawn; + +var slimerjs = require('slimerjs-edge'); + +var serve = require('./serve'); +var listen = require('./test').listen; + + +/** + * Create the debug server and run tests. + */ +serve.createServer(function(err, server) { + if (err) { + process.stderr.write(err.message + '\n'); + process.exit(1); + } + + listen(3001, 3005, server, function(err) { + if (err) { + process.stderr.write('Server failed to start: ' + err.message + '\n'); + process.exit(1); + } + + var address = server.address(); + var url = 'http://' + address.address + ':' + address.port; + var profile = path.join(__dirname, '../build/slimerjs-profile'); + var args = [ + '-profile', + profile, + path.join(__dirname, + '../test_rendering/test.js'), + url + '/test_rendering/index.html' + ]; + + var child = spawn(slimerjs.path, args, {stdio: 'inherit'}); + child.on('exit', function(code) { + // FIXME SlimerJS has a problem with returning the correct return + // code when using a custom profile, see + // https://github.com/laurentj/slimerjs/issues/333 + // as a work-around we are currently reading the return code from + // a file created in the profile directory. + // if this issue is fixed we should use the npm package 'slimerjs' + // instead of the nightly build 'slimerjs-edge'. + var exitstatus = path.join(profile, 'exitstatus'); + fs.readFile(exitstatus, {encoding: 'utf-8'}, function(err, data) { + if (err) { + process.stderr.write( + 'Error getting the exit status of SlimerJS' + '\n'); + process.stderr.write(err); + process.exit(1); + } else { + process.exit(data); + } + }); + }); + }); + +}); diff --git a/tasks/test.js b/tasks/test.js index c9c8a96988..e644dea235 100644 --- a/tasks/test.js +++ b/tasks/test.js @@ -81,6 +81,9 @@ if (require.main === module) { }); } -module.exports = runTests; +module.exports = { + runTests: runTests, + listen: listen +}; diff --git a/test/test-extensions.js b/test/test-extensions.js index e5fd2a2364..73faf238e3 100644 --- a/test/test-extensions.js +++ b/test/test-extensions.js @@ -1,8 +1,13 @@ // FIXME remove afterLoadXml as it uses the wrong XML parser on IE9 -// helper functions for async testing +// helper functions for async testing and other utility functions. (function(global) { + /** + * The default tolerance for image comparisons. + */ + global.IMAGE_TOLERANCE = 1.5; + function afterLoad(type, path, next) { var client = new XMLHttpRequest(); client.open('GET', path, true); @@ -326,5 +331,102 @@ return this; }; + global.createMapDiv = function(width, height) { + var target = document.createElement('div'); + var style = target.style; + style.position = 'absolute'; + style.left = '-1000px'; + style.top = '-1000px'; + style.width = width + 'px'; + style.height = height + 'px'; + document.body.appendChild(target); + + return target; + }; + + global.disposeMap = function(map) { + var target = map.getTarget(); + map.setTarget(null); + goog.dispose(map); + document.body.removeChild(target); + }; + + global.assertWebGL = function(map) { + if(!ol.has.WEBGL) { + expect().fail('No WebGL support!'); + } + }; + + function resembleCanvas(canvas, referenceImage, tolerance, done) { + if (window.showMap) { + document.getElementById('debug').appendChild(canvas); + } + + resemble(referenceImage) + .compareTo(canvas.getContext('2d').getImageData( + 0, 0, canvas.width, canvas.height)) + .onComplete(function(data) { + if(!data.isSameDimensions) { + expect().fail( + 'The dimensions of the reference image and ' + + 'the test canvas are not the same.'); + } + + if (data.misMatchPercentage > tolerance) { + if (window.showDiff) { + var diffImage = new Image(); + diffImage.src = data.getImageDataUrl(); + document.getElementById('debug').appendChild(diffImage); + } + expect(data.misMatchPercentage).to.be.below(tolerance); + } + done(); + }); + }; + + function expectResembleCanvas(map, referenceImage, tolerance, done) { + map.render(); + map.on('postcompose', function(event) { + var canvas = event.context.canvas; + resembleCanvas(canvas, referenceImage, tolerance, done); + }); + }; + + function expectResembleWebGL(map, referenceImage, tolerance, done) { + map.render(); + map.on('postcompose', function(event) { + var webglCanvas = map.getTarget().children[0].children[0]; + expect(webglCanvas).to.be.a(HTMLCanvasElement); + + // draw the WebGL canvas on a new canvas, because we can not create + // a 2d context for that canvas because there is already a webgl context. + var canvas = document.createElement('canvas'); + canvas.width = webglCanvas.width; + canvas.height = webglCanvas.height; + canvas.getContext('2d').drawImage(webglCanvas, 0, 0, + webglCanvas.width, webglCanvas.height); + + resembleCanvas(canvas, referenceImage, tolerance, done); + }); + }; + + /** + * Assert that the given map resembles a reference image. + * + * @param {ol.Map} map A map using the canvas renderer. + * @param {string} referenceImage Path to the reference image. + * @param {number} tolerance The accepted mismatch tolerance. + * @param {function} done A callback to indicate that the test is done. + */ + global.expectResemble = function(map, referenceImage, tolerance, done) { + if (map.getRenderer() instanceof ol.renderer.canvas.Map) { + expectResembleCanvas(map, referenceImage, tolerance, done); + } else if (map.getRenderer() instanceof ol.renderer.webgl.Map) { + expectResembleWebGL(map, referenceImage, tolerance, done); + } else { + expect().fail( + 'resemble only works with the canvas and WebGL renderer.'); + } + }; })(this); diff --git a/test_rendering/README.md b/test_rendering/README.md new file mode 100644 index 0000000000..292d965bf3 --- /dev/null +++ b/test_rendering/README.md @@ -0,0 +1,24 @@ +# Rendering tests + +This directory contains rendering tests which compare a rendered map with a +reference image using [resemble.js](http://huddle.github.io/Resemble.js/). + +Similar to the unit tests, there are two ways to run the tests: directly in the +browser or using [SlimerJS](http://slimerjs.org/) from the command-line. + +To run the tests in the browser, make sure the development server is running +(`./build.py serve`) and open the URL +[http://localhost:3000/test_rendering/index.html](http://localhost:3000/test_rendering/index.html). + +From the command-line the tests can be run with the build target `./build.py test-rendering`. + +## Adding new tests +When creating a new test case, a reference image has to be created. By appending `?generate` +to the URL, a canvas with the rendered map will be shown on the page. Then the reference +image can simply be created with a right-click and "Save image as". + +It is recommended to only run a single test case when generating the reference image. + +## Image difference +When a test fails, an image showing the difference between the reference image and the +rendered map can be displayed by appending `?showdiff` to the URL. diff --git a/test_rendering/index.html b/test_rendering/index.html new file mode 100644 index 0000000000..b0293d06d0 --- /dev/null +++ b/test_rendering/index.html @@ -0,0 +1,93 @@ + + + + OL Rendering Test Runner + + + + + +
+ + + + + + + + + + + + + + + +
+ + diff --git a/test_rendering/slimerjs-profile/prefs.js b/test_rendering/slimerjs-profile/prefs.js new file mode 100644 index 0000000000..c2deee1837 --- /dev/null +++ b/test_rendering/slimerjs-profile/prefs.js @@ -0,0 +1,3 @@ +user_pref("webgl.force-enabled", true); +user_pref("webgl.disabled", false); +user_pref("webgl.msaa-force", true); diff --git a/test_rendering/slimerjs-profile/times.json b/test_rendering/slimerjs-profile/times.json new file mode 100755 index 0000000000..84e52a5d3e --- /dev/null +++ b/test_rendering/slimerjs-profile/times.json @@ -0,0 +1,3 @@ +{ +"created": 1427803527460 +} diff --git a/test_rendering/test.js b/test_rendering/test.js new file mode 100644 index 0000000000..8343ab26c9 --- /dev/null +++ b/test_rendering/test.js @@ -0,0 +1,30 @@ +var url = phantom.args[0]; +var page = require("webpage").create(); + +var v = slimer.geckoVersion; +console.log('Gecko: ' + v.major + '.' + v.minor + '.' + v.patch); + +page.open(url). + then(function(status){ + if (status == "success") { + page.onCallback = function(failedTests) { + if (failedTests.length > 0) { + for (var i = 0; i < failedTests.length; i++) { + var test = failedTests[i]; + console.log(test.title); + console.error(test.errorStack); + console.log(''); + } + console.error(failedTests.length + ' test(s) failed.'); + } else { + console.log('All tests passed.'); + } + page.close(); + phantom.exit(failedTests.length === 0 ? 0 : 1); + } + } else { + console.error("The tests could not be started. Is the server running?"); + page.close(); + phantom.exit(1); + } + }); From c0a23dc8185558cb0bec4fd70ba9a029481236ec Mon Sep 17 00:00:00 2001 From: tsauerwein Date: Thu, 2 Apr 2015 12:11:32 +0200 Subject: [PATCH 2/3] Add first rendering tests --- test/test-extensions.js | 7 +- test_rendering/README.md | 5 +- test_rendering/spec/ol/data/icon.png | Bin 0 -> 2532 bytes .../spec/ol/data/tiles/osm/5/5/12.png | Bin 0 -> 12171 bytes .../ol/data/tiles/stamen-labels/5/5/12.png | Bin 0 -> 5510 bytes .../spec/ol/expected/pan-canvas.png | Bin 0 -> 635 bytes test_rendering/spec/ol/expected/pan-webgl.png | Bin 0 -> 838 bytes .../spec/ol/expected/render-canvas.png | Bin 0 -> 637 bytes .../spec/ol/expected/render-webgl.png | Bin 0 -> 801 bytes .../spec/ol/expected/rotate-canvas.png | Bin 0 -> 615 bytes .../spec/ol/expected/rotate-webgl.png | Bin 0 -> 733 bytes .../spec/ol/expected/zoom-canvas.png | Bin 0 -> 639 bytes .../spec/ol/expected/zoom-webgl.png | Bin 0 -> 799 bytes .../ol/layer/expected/2-layers-canvas.png | Bin 0 -> 4074 bytes .../spec/ol/layer/expected/2-layers-webgl.png | Bin 0 -> 4085 bytes .../spec/ol/layer/expected/image-canvas.png | Bin 0 -> 3237 bytes .../spec/ol/layer/expected/image-webgl.png | Bin 0 -> 3986 bytes .../spec/ol/layer/expected/opacity-canvas.png | Bin 0 -> 2543 bytes .../spec/ol/layer/expected/opacity-webgl.png | Bin 0 -> 2541 bytes .../spec/ol/layer/expected/osm-canvas.png | Bin 0 -> 3237 bytes .../spec/ol/layer/expected/osm-webgl.png | Bin 0 -> 3237 bytes test_rendering/spec/ol/layer/image.test.js | 94 ++++++++ test_rendering/spec/ol/layer/tile.test.js | 155 ++++++++++++++ test_rendering/spec/ol/map.test.js | 124 +++++++++++ test_rendering/spec/ol/style/circle.test.js | 201 ++++++++++++++++++ .../spec/ol/style/expected/circle-canvas.png | Bin 0 -> 1896 bytes .../spec/ol/style/expected/circle-webgl.png | Bin 0 -> 2570 bytes .../spec/ol/style/expected/icon-canvas.png | Bin 0 -> 1230 bytes .../spec/ol/style/expected/icon-webgl.png | Bin 0 -> 1281 bytes .../expected/linestring-strokes-canvas.png | Bin 0 -> 787 bytes .../polygon-fill-and-strokes-canvas.png | Bin 0 -> 517 bytes .../style/expected/polygon-types-canvas.png | Bin 0 -> 276 bytes .../style/expected/polygon-zindex-canvas.png | Bin 0 -> 300 bytes .../ol/style/expected/regularshape-canvas.png | Bin 0 -> 1239 bytes .../ol/style/expected/regularshape-webgl.png | Bin 0 -> 1551 bytes test_rendering/spec/ol/style/icon.test.js | 85 ++++++++ .../spec/ol/style/linestring.test.js | 102 +++++++++ test_rendering/spec/ol/style/polygon.test.js | 200 +++++++++++++++++ .../spec/ol/style/regularshape.test.js | 129 +++++++++++ 39 files changed, 1099 insertions(+), 3 deletions(-) create mode 100644 test_rendering/spec/ol/data/icon.png create mode 100644 test_rendering/spec/ol/data/tiles/osm/5/5/12.png create mode 100644 test_rendering/spec/ol/data/tiles/stamen-labels/5/5/12.png create mode 100644 test_rendering/spec/ol/expected/pan-canvas.png create mode 100644 test_rendering/spec/ol/expected/pan-webgl.png create mode 100644 test_rendering/spec/ol/expected/render-canvas.png create mode 100644 test_rendering/spec/ol/expected/render-webgl.png create mode 100644 test_rendering/spec/ol/expected/rotate-canvas.png create mode 100644 test_rendering/spec/ol/expected/rotate-webgl.png create mode 100644 test_rendering/spec/ol/expected/zoom-canvas.png create mode 100644 test_rendering/spec/ol/expected/zoom-webgl.png create mode 100644 test_rendering/spec/ol/layer/expected/2-layers-canvas.png create mode 100644 test_rendering/spec/ol/layer/expected/2-layers-webgl.png create mode 100644 test_rendering/spec/ol/layer/expected/image-canvas.png create mode 100644 test_rendering/spec/ol/layer/expected/image-webgl.png create mode 100644 test_rendering/spec/ol/layer/expected/opacity-canvas.png create mode 100644 test_rendering/spec/ol/layer/expected/opacity-webgl.png create mode 100644 test_rendering/spec/ol/layer/expected/osm-canvas.png create mode 100644 test_rendering/spec/ol/layer/expected/osm-webgl.png create mode 100644 test_rendering/spec/ol/layer/image.test.js create mode 100644 test_rendering/spec/ol/layer/tile.test.js create mode 100644 test_rendering/spec/ol/map.test.js create mode 100644 test_rendering/spec/ol/style/circle.test.js create mode 100644 test_rendering/spec/ol/style/expected/circle-canvas.png create mode 100644 test_rendering/spec/ol/style/expected/circle-webgl.png create mode 100644 test_rendering/spec/ol/style/expected/icon-canvas.png create mode 100644 test_rendering/spec/ol/style/expected/icon-webgl.png create mode 100644 test_rendering/spec/ol/style/expected/linestring-strokes-canvas.png create mode 100644 test_rendering/spec/ol/style/expected/polygon-fill-and-strokes-canvas.png create mode 100644 test_rendering/spec/ol/style/expected/polygon-types-canvas.png create mode 100644 test_rendering/spec/ol/style/expected/polygon-zindex-canvas.png create mode 100644 test_rendering/spec/ol/style/expected/regularshape-canvas.png create mode 100644 test_rendering/spec/ol/style/expected/regularshape-webgl.png create mode 100644 test_rendering/spec/ol/style/icon.test.js create mode 100644 test_rendering/spec/ol/style/linestring.test.js create mode 100644 test_rendering/spec/ol/style/polygon.test.js create mode 100644 test_rendering/spec/ol/style/regularshape.test.js diff --git a/test/test-extensions.js b/test/test-extensions.js index 73faf238e3..c9cdac18a5 100644 --- a/test/test-extensions.js +++ b/test/test-extensions.js @@ -395,7 +395,12 @@ function expectResembleWebGL(map, referenceImage, tolerance, done) { map.render(); map.on('postcompose', function(event) { - var webglCanvas = map.getTarget().children[0].children[0]; + if (event.frameState.animate) { + // make sure the tile-queue is empty + return; + } + + var webglCanvas = event.glContext.getCanvas(); expect(webglCanvas).to.be.a(HTMLCanvasElement); // draw the WebGL canvas on a new canvas, because we can not create diff --git a/test_rendering/README.md b/test_rendering/README.md index 292d965bf3..8f305068a4 100644 --- a/test_rendering/README.md +++ b/test_rendering/README.md @@ -14,8 +14,9 @@ From the command-line the tests can be run with the build target `./build.py tes ## Adding new tests When creating a new test case, a reference image has to be created. By appending `?generate` -to the URL, a canvas with the rendered map will be shown on the page. Then the reference -image can simply be created with a right-click and "Save image as". +to the URL, a canvas with the rendered map will be shown on the page when calling +`expectResemble`. Then the reference image can simply be created with a right-click +and "Save image as". It is recommended to only run a single test case when generating the reference image. diff --git a/test_rendering/spec/ol/data/icon.png b/test_rendering/spec/ol/data/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..ed886623d54cc7972175302fad216a541dd349c3 GIT binary patch literal 2532 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 literal 0 HcmV?d00001 diff --git a/test_rendering/spec/ol/expected/pan-canvas.png b/test_rendering/spec/ol/expected/pan-canvas.png new file mode 100644 index 0000000000000000000000000000000000000000..f9c84f316d63f3ab4abe76d462946c22707ee820 GIT binary patch literal 635 zcmV->0)+jEP)ZVtK}REvqcK9GfF;}5(HJ2+=xC&IG)8C?uw)xM8Y5%}9gQ@O#t4l9 zmTY53c8nNJKbyeF_&=VFnThT1|Nnpg{Qr0M-#?a#7cvbWkR7BHY9uK}4CbE~VE*;@ z05cP#ijFAv2`)CK?;!i{y!)>5`s;6v|Nj^h&t)1fpwLZZX(!1e#xu`c;Ow zC&$MQ_5=*H9(-iE{^sih1_p+}v*{)q$Z`z@nuzuYC^@mPFicq;rd^Hh37Gx4+i&}x zc>GE4OuC6Y1#TisE72Y?o^fV_z61}?Tz~adxNLg#=_hB|4zyFRGGEEPV=_azY5$zGPS!WKL$?$y`@*Xjs zd1iq)H=Fs^Xx)BXLALPX3$@87pBDdRV-~!SX!wDwpe0ii(J^8${k#G*)8G4n>Y@v( z?d6W6+Xu=Y@$0YWfByOR(AjhoQ0YZiK(t3dt^!wtO#kOw$?|V5v6kHnE4@H5vEags zpszpwe*MkHY)kLh0J)7MkAO57&pZ>r$iOh^KLdj-T97aN%f?(V5S}2*BQVDs%sOwt z@b`}Zn9sp-VW2z!a}UWeLf3>(f@Px~AtA8nqI5Jy=n~8%STY(TBm@>+ln$F10RZ-| VqBCAdP}2Ya002ovPDHLkV1kQpATa;{ literal 0 HcmV?d00001 diff --git a/test_rendering/spec/ol/expected/pan-webgl.png b/test_rendering/spec/ol/expected/pan-webgl.png new file mode 100644 index 0000000000000000000000000000000000000000..49fe4e01aae0060aef18b39dcaab395f8cc07c76 GIT binary patch literal 838 zcmV-M1G)T(P)HMb%p+t$HHy@Bv_yk0y6aEyE{U8s5=atA zL0Nhs?ZQ|vH(ye>ofI{6Zko%N9n*AYu?xWqgX8n?V90asKfmAi<#!H;B#y{K9uXe| zHuAqUi5tOd7I-Xf1UNcGAZ`Rvu)t#v+(=|@p)xu}ry(gqMNmA+^VC`>M7n(A zu1R9XvI(pN5)^KvtW2bc$|;a%X|5~sigM-R2&sr7d2Tznv$DxA`kjNHJ$>!H+_=pP zsR;-dY(zmnGNe?Qn(`85X(gxRlkrlKUlc(Fe{Tn+qdqSE>)g6z+F|Wp=rMP#v-Y1r zY9Js%M#ATmTyA=Dp|rH5Mxz`kN{*QpQv|=ecXo9vy6cBWjwtr!zjj z%V?DobauRRzkORgLABZD=#G&k&rpMofzSkm3Nn&Z#ncrWn~jWKJ$yAImi^Zzv%_22 zW}9DjJS?aMQUd`AGeVp0oW0dtSFcmC)j0_x`|a~_+tN0>hkoZ?b`I6+n;|p-p@NL4 zD;Ukm>c*$#r{%G=T2+5ajCgJDw(wbfaxa~EHM*!9AN=x$ZE0u)QUd`AGD4)5NiwUA zx6`$T`xn#X{)((PM`oOCIsDRxo3Q>^N&7hE&mZw^xM$y*TYWt*#~?HTp~8$11QGrO ztFM@Ds`HEKyu?UxMy!OB91{h-fi2naLg4s(;LpU0+uq6AI<17ovIC?B0upQ_ydx@0 zA0M4vXpm*=4JR`73NpltLKGR`*g^NIbI9W3T&}|~5!QAfBfEhmR5U78l@C%Wl9vQ2 z(!2h;b!NuWacKWpz(yc002vC@2r@MggRv2a@Q|Rm5hSrf48@H=gogzE3l|RTGy5?} QjsO4v07*qoM6N<$f{2rUDgXcg literal 0 HcmV?d00001 diff --git a/test_rendering/spec/ol/expected/render-canvas.png b/test_rendering/spec/ol/expected/render-canvas.png new file mode 100644 index 0000000000000000000000000000000000000000..ed50f1d7d2b72d546d2a5fdbb6fb438e57ed66dc GIT binary patch literal 637 zcmV-@0)qXCP)ZVtK}REvqcK8Ez#2_Io50BUKc0=5iS6(I|9}7d|9AG^KbDCXG7TRP zqn{KtG>H*|`R4_gfBikc%*3doBg%b(i;d|!$WeFReOGz?^|!|Ve~gLeGL09I;!r|r zY2p#%nP)EYvoj0K57g|F<6{SV0tQ+SKC)bY^K}9P14H21bdwE)97wD@)ja}APAn`8 zQ&xv*SEG9Z=BV85w|!4M{-k#%-9(;PhZ0gpb&nX&II}@tf`@0Wzxpa%mOuLRlQU?= zl?i_tnGG+b8D1ddNMhuv?h(s5XO9_6@xGnxsk#}T159R}o%#3Qf5!`%rU!^|C?Pde z_lVi7Gl$J&_&yAIj~LH9vp}4i&3tRLZa=P2TzK(?+T@c@i~q7Q3tmVx{6HwQiIJyz zj2KKmufWXo_kN(d=z?l{x#Q@L0OgPP_1E)1|NMLCY`O`k^r8x&x<^2+0#}4g|L0rD z@^3D&mfZ_0y+ARs;KGZbuRs5O{msT~ORd-d*+~4vC?;im$pM&KBwLJi{hh{NCm4r`%A)_84A+YG8bTmfj63ir6 zG8!W!1QuPCj>ZUGf|&$MMq`A8z@m%N(HNmiFq2@(XpE2$SaeZ38Y6TGW)dtJHZcMK XFBQ9Ytk*4mmAD!SE_+ zE+Z3hq|(%vp!jC@#j$1^Sj^g zY`^9=`%lT|H@eN2l!NZA)YCc`Y023pB)|BJN}qBy)3XQK>-Tq_v-*9e^!Pny_q^{* zuJL&Fd;DH@Ov?4?(Irw|F`q-lclMo~X#d~P;H=HxBjpE=UO#_sx%5&#pt7G!)n>Xs zbz3Us9seOja98W;iJQ;u{V=og*UQ_*l4_mJmzDQvPTciyr)Q?yr0q>6uKG#EPfoAj zZ<#)?_Sx=-&u+hdez~WZeX0ABy+OPw&6~XLPGxNo;#K{A>htD$r!ozV$lU!uqmnN! z4R;GaFB4n3TD|tvf-fA+P0a0C0U<4u7P{`4yy$?nzUjl_Rfl5o9cRjk2p^ZP4Y*VG zeeS=b)9>fm#n@+`I=$9-9gknXfq_9oS3>6YDFT_b#qqL+d1a!Ced}e`=+wv8{5)Cu z@Td5;>=ospi!(v6xrK#B5d_d(`v)|HeP* zNq;_ly*6{U{QCL!A3nYAmA>+Y<%Hj=u#OiCwO>tDReU*l&4D97`XB2HKkhz%dbv$S zK?38|+mR;UIkryXHGFo##I2){Ve6His+K54Pu*g-Wb$Z+nPqQ`jkqn>0+T+2r>mdK II;Vst0D_i+I{*Lx literal 0 HcmV?d00001 diff --git a/test_rendering/spec/ol/expected/rotate-canvas.png b/test_rendering/spec/ol/expected/rotate-canvas.png new file mode 100644 index 0000000000000000000000000000000000000000..e614cf3c0858d3a802822c2595545b11c696150d GIT binary patch literal 615 zcmV-t0+{`YP)rA{{R2?&;NgC|NUc`cp=m90X;lT zandrFe_nw3*WUxoOpGczqTDCA*qFY99De8Bca_&)e{1~z$C!97(|7@`JwvfajAx#? z$j{C!Fh5YUPmYfr>0^+T@c@i~q7Q3tmVx{4gkE#9;b)1!ktd_XE{M7gXEJ9Y=R0D1XGS zzn=g3=iftT(@j977tH`gc?9Gta7D=Uf4-G0|K<{F*}bsR3ltLzF1!f(`t$GC-)zjb zw2TdqJ1F)D$PnY1X95@*7$*H^V30)%@`Zodm*UBP0YCU6hW-2wj4i z1WQI^goMDNi_*~;p-V86V998VkPujOQ95j51OTw!qBDezk)i+q002ovPDHLkV1k+s B9_|1D literal 0 HcmV?d00001 diff --git a/test_rendering/spec/ol/expected/rotate-webgl.png b/test_rendering/spec/ol/expected/rotate-webgl.png new file mode 100644 index 0000000000000000000000000000000000000000..014481d84be0b94038498e62795e34ac586ca071 GIT binary patch literal 733 zcmV<30wVp1P)&wTYOT|u085kJ; z($X^&d&F?^kzIV;T&n%v>hqNOIX*BkK|=rEzrV~Ajz2Tqdi#yfudg2xE)=?Krln^n z@(3t7aR^CFo9U-MNne8J6%$$#`u6)DOU0f$J|`c4mOqtlV$8t6@Pk&dLXk%dCLUR= zBP%R3$46~7J1f&4Y>vGB?mJ(?hU?9rK7O*jQsj7MP z>bXMqmke*-fMSTIo}i{jXc^cZVtK}REvqcK9GfF;}5(HJ2+=xC&IG)8C?uw)xcwHPs)el~%T@qauU zGZWk2|NsB~`Ty_izke(fFJu}%Alr2$Xr$O92J_DgF#q~{fSHL=MMsqT1Q#3AcaZ&e z-hEej{q?uT|9^~$=Q52Kkl-e=lv3;wsZ)WVw(?O%!GM1kC>2?YDhTJpQD2Cf!7yNH>wCj3SR1 z&p5L|UxJ5cuD|*!T(&>@^pi7a#gz$v8JP_)q#0fy%aufEqR1nbbIu+!mg0Ro*;92h zKD$h2ot^pj-+#vonWhJba1&WdDDsHetTTtrWcWS|d5;*+JhMQYo6US{v~EAHU|e|d zh1%qkPmBMuF$-QuH2gqTa1)`4q8KrleqMo@>F@nObr$iOh^KLdj-T97aN%f?(lYfn(kBQVDs%sOwt@b`}Zn9sp-fgT=!*-e!g zp;^Kw!QfGkkPujOQ92qUbO~k>EE$av5(0}ZN=IXaF2PKKC8IGyLSWHF>1d45C74OD Z1ORP6qBC2Iul@i4002ovPDHLkV1lb*BD??q literal 0 HcmV?d00001 diff --git a/test_rendering/spec/ol/expected/zoom-webgl.png b/test_rendering/spec/ol/expected/zoom-webgl.png new file mode 100644 index 0000000000000000000000000000000000000000..f89e01ad6860e03b459ed5ee4b064021fc849a5a GIT binary patch literal 799 zcmV+)1K|9LP)ZVtK}REvqcK9GfF;}5(HJ2+=xC&IG)9mEmRs9Yf=}MafRTwol7Zm- z@1GAp{=Is4{mlMnJ7@3sdiC@RT6=~fkBIwbTFCpQ{-#Tl>=UZpr(9$zxdjyo6WZY88;aCk24%N@Mq9^1mrMYHDeJzbyEv2bz=)2Rbz3+|NmJ2GckVo zdh5*1kJry1c=`3l4O)8wiBeV=%a?Bo$5pqI}mU>2GgqER8 dj@iQ|MgUks>@#{P9|-^e002ovPDHLkV1ih=j%fe@ literal 0 HcmV?d00001 diff --git a/test_rendering/spec/ol/layer/expected/2-layers-canvas.png b/test_rendering/spec/ol/layer/expected/2-layers-canvas.png new file mode 100644 index 0000000000000000000000000000000000000000..ad069af45cf502de3816a0ff264d61a6a579058f GIT binary patch literal 4074 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 literal 0 HcmV?d00001 diff --git a/test_rendering/spec/ol/layer/expected/2-layers-webgl.png b/test_rendering/spec/ol/layer/expected/2-layers-webgl.png new file mode 100644 index 0000000000000000000000000000000000000000..a982b089de138ee2d9f4ef5a95c8228cfcecf64c GIT binary patch literal 4085 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 literal 0 HcmV?d00001 diff --git a/test_rendering/spec/ol/layer/expected/image-canvas.png b/test_rendering/spec/ol/layer/expected/image-canvas.png new file mode 100644 index 0000000000000000000000000000000000000000..86f9bedd38c9154a70155599b9619e02019d4321 GIT binary patch literal 3237 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 literal 0 HcmV?d00001 diff --git a/test_rendering/spec/ol/layer/expected/opacity-canvas.png b/test_rendering/spec/ol/layer/expected/opacity-canvas.png new file mode 100644 index 0000000000000000000000000000000000000000..a69bb84d8546f0f5be388f299f3102bcc520c1de GIT binary patch literal 2543 zcmVvS?~&4vSh(q67U5yB*etTL_|bHFHKId$zH?mPRx8&Ye*{{rL6kGlsEs7FwzDarO7>(W7x1&g#3KzvrRXgGcQ& zDwp3GVgj#yeQ+0l{`}G*4Oh5YYc)QN4dKOIWdYna=GX@GKH+J{=RamlH>dXzr!L}g z`#wk8M;zK96Q-Et9yjydkbDo$Y1G!-wX(x0Af|+e&Bqw?cFZ0rUgo0t!)>K^7%d?s zAZCAPC`8TwtC1o6+$Eq=uv(#U_bu-GTaTvFXsY{+U)!OVy+`HL`Ca={K-UE{wZW!- zfB(zDBgO=y6}Gj3F=InGLj=%gV+fVn7+AB8fs_)yzxLQ}tnB8W42CP`<)(0|o4;!>1qr{r59HFpKZOsOE-eUJgCr6E*|ze%FBVJPkQ^0l_Cc?(Awb z&@0~_9RBmt;h(1ppML!B*Jmzb))Dtgss`mI!u7wM?7wfyk9}@#N;36T) z3+RD*WC*<#0X48Ov;UMu_-Ayn59MdPbYHm{3pQgf8{4%Ah?uNot!W$>;3p+w!PbD%z}4 zsH~YWq%4{q7$<8Q$Z2#*luMH)y!itj>~7vGv6btmqecj~7;2K#rf*EZ&wYf1y%@pO+y@*%_$g-zNSi2Dg71g2@W-UOyIw$TcoxIb>G*A3~DB}ZKL61#Li{8 zakcR&EwW`vjPr)f;e^+iQdlnxG)zP0>KB6d<>-Y`PGOMM!|JFK2vSAT81#~>NFo|$ z&{Xtvem8^(nJbp+ByJi#KW_+Gii4q52EpzWHqOY75~Oo9TpoXZ?eVxZSB9vh(Dh05 z)Uk~)2BKhT1H+Z06ipeE0S0!~^Stjv#HpRjBfL9g^K)3y8$O9tp(1XFU0zeiKi_&h z&=4PFVcc!*GV!4YA;?{3NGT{Ol9XnJkwj=PVCjhfkB7Qi)m@xx-Xl{(xDx*89K!U7 z(6J-+X`#RAV3MQ9Sk|x@O1eXLaM(5kd48T$O)o?rvD?}UX~LbR=h`md+tYfIBw;Lv z76Wv=zCtQvUB>Wtz{Z*@*Hc2A+QAzJP%0uuGb=2Mf}JBKZphPiy*!}N%L#FgdS`fC zF0mLgMs}Xz#?PlNNWD!U#|T89G4Ri0CHE;Y+Ac~MB_Hu+Vb??AW-wu{SFH0|>mDP< zMvYn;!~$!6CcC$j$F4ExW0c73yM%3RrTP;i2bIwKfVwt|6{b%fF~wCKc4^3xJSkMN zq#gz`C^!;!vj%U629m6;>N7*Wtwb7<^O9tQfN7@O;p5g)`;idwu$ zSCTZi3C4LmHVt0hrt~|95gNmqo}+kTT6|5tLR!|GFd&93J*d&tK1|P#&`YI2yDW9bSeRq2l5Y7NJ$Ea-2$eSFmWnnfJAAE(u z=@{_k@m(x3xk=-#F<@9NRg5fe**bmPSYgLM%OhtrPAbabI_Xw3hX80cI=4HAA)QYT z#E?XYj@zzTnp?E7TLm~njo#o`SHJh<6TXM58aFJ;YITPS4fcne;i;XB1A2z0%3_h- zndg1(QI$byzS|}#eebClzrS@W^~hRrHTFcI>~U!<7y_J4vZIAsDew8(y2Kmto@8U^Z17F?l+ zv_*TeAt@Q}Mc2JXEQi(=3nhSwZafIyA}XgWM#GphG>fB%jcue;!t71u+xlE=k z5jUHC(TvO09!~xr)y6Vs#tVkAmCnZW4<`HC-{2SwA3@KQe zcJ&9gRi?+zUiN&YF&6_|A+5-0{QLhBipmL8`}4S{nmDr`%|oNjnqZ8$IfnMbAp^q6-JvpVd{vd z`cf<|E#>1p!WpLQMMKEi_Byo23ld`v1U_YeK~zC7gJA9k{ogf&lx>(Nf>7}4NWk-J zCxVe3d&wxnf#YtRWKYlWMZ$7*?4g zJOeh)!IW}wSoXg4FxJn8R4k9}lL_oRf!}ALiL#L$TmlW!2%H8)JD+JUwi^`)vp)vgC!`#u^M;O9) zFd?#FS~$YX?WN%qc{C?4vn$E&*Oy8DV7{ReD29|j`#;%`JIOht7l!}<002ovPDHLk FV1nbW+!O!+ literal 0 HcmV?d00001 diff --git a/test_rendering/spec/ol/layer/expected/opacity-webgl.png b/test_rendering/spec/ol/layer/expected/opacity-webgl.png new file mode 100644 index 0000000000000000000000000000000000000000..389d138042281eba1b7b100b30e12030d2b1d9e5 GIT binary patch literal 2541 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 literal 0 HcmV?d00001 diff --git a/test_rendering/spec/ol/style/expected/circle-webgl.png b/test_rendering/spec/ol/style/expected/circle-webgl.png new file mode 100644 index 0000000000000000000000000000000000000000..89c37e992ec5f4265fea3b30c9b70218694f70ee GIT binary patch literal 2570 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 literal 0 HcmV?d00001 diff --git a/test_rendering/spec/ol/style/expected/icon-canvas.png b/test_rendering/spec/ol/style/expected/icon-canvas.png new file mode 100644 index 0000000000000000000000000000000000000000..cdc0dba6b16291c733c126679e0cf0782e350356 GIT binary patch literal 1230 zcmV;<1Tp)GP)574^ZcIY z{l1wIxJwSsy-u(f|kcG53<_P>*)KQ?oE@K)eTEnre&Z&ke7t zf$J%-NzmWaY8sZ(BBW7Xy|c4rGL^sIaVi-}q^S1gnfj@SU)@rR-a zYN9LJb<=oF2e%bl`CvkI7pAcxaOF-@$ruQ~Mf~cn0Fv90)}+{-6uW)wU-|`Snj3iL zgW1?*3(321L^*@4#DN%&8KGYbom4pZClHi^H&p&bunxGLaN`c zV#=!d)HR+(aM`hqE+%;Dd=`T2J%htnz_ItLaairF_~sKH9$v;kS0N4U%~X^>#=g2A zne*u~qyj6JvMdFO)tp6eJJ>#NHO;}xw1nDNHg#V5yeDvkOW`)$4i}X>)*&iZETsdo zFA?!X#2-CSkE__j$t7Rm%lD+$%Fm4fN(YU=k*tX^6%rVo+q{q3-Mg@g1K2g51jMYRzdRkHV7= zjH9@~n;xazb%z<^8c6xD`_tF87tT=ERFCMhBNZtGe`$J_&rfz{#d{=w`{Z$6$Kd73 zV;AVU97426ApWyb>oqRJEpA_I<(Px zFh=US#=rhaB#@joa9QXMw5;gadX6aN6KXhZI!??=}h-r5)lC1R4X shTG;6F>IYlg}FpbGS+b0yC#u80q%OhX4Qo literal 0 HcmV?d00001 diff --git a/test_rendering/spec/ol/style/expected/icon-webgl.png b/test_rendering/spec/ol/style/expected/icon-webgl.png new file mode 100644 index 0000000000000000000000000000000000000000..c08cbfdd549f1d5d68ec8e7b96ce554c5a8a4fd0 GIT binary patch literal 1281 zcmV+c1^)VpP)$bfBj1II*TWE0s2xXLYzJ4K)rT3UKJXK9(!M7zYpIY~o${yTrX?|FXD z^S%B0eFT=sLo5*v2nLeanzR18Yjij4TqGPe0^siN5kY}-!Qq%NU9C+xa563|ZdM30 z1pz4-t6o-YXgcG#HYBrN>;h+X0<0H#6hLYM!92GD_Nm!sQ`&_?J_AzNe{M&yzG2T) z(FJgJ7YHf+zuGt_3t4m+$ki(D;4?e7rpLXr=u`wrB!8$brJ(+-)_kS~lsXU~$^SrN zSFc6)$lsVY-=)>*0-<6cjg7#;RXgAK@a5$3#ik-0h^|y?u5JUR3IIqTh*2P1rAA}c zH@Gp_gIDrWA)}=*+bw{T^MJ^njzD_UHs1m%a)Z=$fK)QrpQuG*Ogs*kA4mEAVoY01 zc>9aPs7yPK?M3_0)~5#<%s{e!xo?74&i@5Qqe9Ckl?aqE$g4etn5bwhQ>xKx7{IF= zUP43rRqQ#P4Khdy$&=we2=Zg8*7DO$5UM~_?kmE;#3%+P$B?`I0}L4r(EWKCgGK{F z0)z2!<)@$&QqYfw`6kHR&)o=KuErlZRnRC@p80L=Ye#g%N(3=-&wI`9zaZsQ1_-$X z^kZrt1gS68&NcRcQp-{G{xNhJ`jNVE2Zp8%P|KAFkTA%s{TyKm6|!o+1mra6s1V-+ zDQGyWwKerX8KFUIMwv&rLKcAd6T7hai5HQ+DFxHkSzPXEMe^5~3m}myq(}PFuU6l; zZx%P#yl1ZO02Qjh=CyGM4-WAxrP{V8JfaFm%!)Oh_m+M=I{G_7s2R}VK}dUO)3!s2 zyNy1vj~wZ&h%4!C%ynMthiPOAr0mXyc#l91AXp&mg*7nV8n;ZO{gAj=2zR|88{(1P z3gz)GUA1D^Nh%=&!Mgu2dT;Gi&@f8oVQlZcGLv&D(`P{3LNwncM+&c%A= zAV?AfBLNf?Hkd+kbq7v2`V`2~j*4fG>FbWV2B*Q99bnxs_jyPO1u~R@b9!dH`uUHN z5)u-eJ_X_yqpo`W1ZiZ~u@e@s^UiyYBqT+G2$TRS31Y39eBIu!bV5J~HY2yi zapP8SbN?#(J*-12Vbmek<~m+QSka1f5;NOjq3`P3X8!%kTM+rr=z z3Mn9`VAT)iS&FaM3kf0k(z-1!^n6ki{SM2%=%@96o0*{OvQLAw&al zHx4b^`Y7p?o+LO@qjol$gX4~%j;==QG9|gEsvUb(6|UWwNA4!Nc+?-d)v5S z?)#gCn6&pJ3-e;Yhywz+Zy%%p9tNPm!kx-30Fwah@OoFoKNPV*_$%UB=?CFyoM>hK zL`1WeXJdaNJdG2r%%6y8*79uZPlTs&qLuj*5zShjjs1!6G)}ZKe{-Kl z`V7Wdd^E`Kf0x;9CkTm|m3f1vw_86O)`%70_wMclY=IDj(&j*PE==lNXTb zG&>eToY1L@i{^kF9C(7L`nUtchbki+wzhoicCqcWwP--W>`K|3Vi#gj?AOl49u}$Q z%xb5OG$+3Po~$$CAG2y_tTSSXZwBC2y|V+L^qiC;S5;(0L+CTx9RR{qI;sHSd2I+_ zsyu%WfM=vpl_aS_Oo(meI5R>Rf>2Su6-U6Wc616>mFi7X{1&KNI+y zv@OSgm=L^VW@c=Iz$|{kB<*COAarP~GT{oLAsGPO$$kPjw$Zyh4*@X+?@@IqU*%?3 z)5@QuE&GC`fY1Rpn*{5HSqdJ$Ag18)?#nk5%Z{D`_^Q^4YRf(#%c`A93v^qK>SV4U zt5iF9D;N{aPDYqdA&a_zxC&l~eLaUTxjK^twPhPf9S}ur*+pF61g;FkSG8j@qUY`c zxKe+-+VU!p5YL}Il#XSPl!9loZF^3E+;Tl&7J+Dm z)bU+t>Jbs_75kA#xo<# R=Sctn002ovPDHLkV1i-ebbkN< literal 0 HcmV?d00001 diff --git a/test_rendering/spec/ol/style/expected/polygon-fill-and-strokes-canvas.png b/test_rendering/spec/ol/style/expected/polygon-fill-and-strokes-canvas.png new file mode 100644 index 0000000000000000000000000000000000000000..b1b5d9d4d0ecc2a681120c79310705e5b63d8f67 GIT binary patch literal 517 zcmV+g0{Z=lP)FvI2O5}Ct=z=yj zFNBEhku0Po6_FkhX#vEKUm7~(8INC2IW;|kSDsq72V&GYVmfxi?5xfa4b1mqy@|pO8mvx|N;R}(pGMN@mZYuH(Z9CjT3ZNDj00000NkvXX Hu0mjfP5JF2 literal 0 HcmV?d00001 diff --git a/test_rendering/spec/ol/style/expected/polygon-types-canvas.png b/test_rendering/spec/ol/style/expected/polygon-types-canvas.png new file mode 100644 index 0000000000000000000000000000000000000000..4abfccb058171eacee2eb2426f37ed59671ecfd7 GIT binary patch literal 276 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 B)f@l- literal 0 HcmV?d00001 diff --git a/test_rendering/spec/ol/style/icon.test.js b/test_rendering/spec/ol/style/icon.test.js new file mode 100644 index 0000000000..d89bbd8a5f --- /dev/null +++ b/test_rendering/spec/ol/style/icon.test.js @@ -0,0 +1,85 @@ +goog.provide('ol.test.rendering.style.Icon'); + +describe('ol.rendering.style.Icon', function() { + + var target, map, vectorSource; + + function createMap(renderer) { + target = createMapDiv(50, 50); + + vectorSource = new ol.source.Vector(); + vectorLayer = new ol.layer.Vector({ + source: vectorSource + }); + + map = new ol.Map({ + target: target, + renderer: renderer, + layers: [vectorLayer], + view: new ol.View({ + projection: 'EPSG:4326', + center: [0, 0], + resolution: 1 + }) + }); + return map; + } + + describe('#render', function() { + afterEach(function() { + disposeMap(map); + }); + + function createFeatures(callback) { + var feature; + feature = new ol.Feature({ + geometry: new ol.geom.Point([0, 0]) + }); + + var img = new Image(); + img.onload = function() { + feature.setStyle(new ol.style.Style({ + image: new ol.style.Icon(/** @type {olx.style.IconOptions} */ ({ + anchor: [0.5, 46], + anchorXUnits: 'fraction', + anchorYUnits: 'pixels', + opacity: 0.75, + scale: 0.5, + img: img, + imgSize: [32, 48] + })) + })); + vectorSource.addFeature(feature); + callback(); + }; + img.src = 'spec/ol/data/icon.png'; + } + + it('tests the canvas renderer', function(done) { + map = createMap('canvas'); + createFeatures(function() { + expectResemble(map, 'spec/ol/style/expected/icon-canvas.png', + IMAGE_TOLERANCE, done); + }); + }); + + it('tests the WebGL renderer', function(done) { + assertWebGL(); + map = createMap('webgl'); + createFeatures(function() { + expectResemble(map, 'spec/ol/style/expected/icon-webgl.png', + IMAGE_TOLERANCE, done); + }); + }); + }); +}); + +goog.require('goog.dispose'); +goog.require('ol.Feature'); +goog.require('ol.geom.Point'); +goog.require('ol.Map'); +goog.require('ol.View'); +goog.require('ol.layer.Vector'); +goog.require('ol.source.Vector'); +goog.require('ol.style.Icon'); +goog.require('ol.style.Style'); diff --git a/test_rendering/spec/ol/style/linestring.test.js b/test_rendering/spec/ol/style/linestring.test.js new file mode 100644 index 0000000000..bb8921f4a8 --- /dev/null +++ b/test_rendering/spec/ol/style/linestring.test.js @@ -0,0 +1,102 @@ +goog.provide('ol.test.rendering.style.LineString'); + +describe('ol.rendering.style.LineString', function() { + + var target, map, vectorSource; + + function createMap(renderer) { + target = createMapDiv(50, 50); + + vectorSource = new ol.source.Vector(); + vectorLayer = new ol.layer.Vector({ + source: vectorSource + }); + + map = new ol.Map({ + target: target, + renderer: renderer, + layers: [vectorLayer], + view: new ol.View({ + projection: 'EPSG:4326', + center: [0, 0], + resolution: 1 + }) + }); + return map; + } + + describe('different strokes', function() { + afterEach(function() { + disposeMap(map); + }); + + function createFeatures() { + var feature; + + feature = new ol.Feature({ + geometry: new ol.geom.LineString( + [[-20, 20], [15, 20]] + ) + }); + feature.setStyle(new ol.style.Style({ + stroke: new ol.style.Stroke({color: '#DE213A', width: 3}) + })); + vectorSource.addFeature(feature); + + feature = new ol.Feature({ + geometry: new ol.geom.LineString( + [[-20, 15], [15, 15]] + ) + }); + feature.setStyle(new ol.style.Style({ + stroke: new ol.style.Stroke({color: '#9696EB', width: 1}) + })); + vectorSource.addFeature(feature); + + feature = new ol.Feature({ + geometry: new ol.geom.LineString( + [[-20, 10], [15, 10]] + ) + }); + feature.setStyle([new ol.style.Style({ + stroke: new ol.style.Stroke({color: '#F2F211', width: 5}) + }), new ol.style.Style({ + stroke: new ol.style.Stroke({color: '#292921', width: 1}) + })]); + vectorSource.addFeature(feature); + + feature = new ol.Feature({ + geometry: new ol.geom.LineString( + [[-20, -20], [-2, 0], [15, -20]] + ) + }); + feature.setStyle(new ol.style.Style({ + stroke: new ol.style.Stroke({ + color: '#000000', + width: 2, + lineCap: 'square', + lineJoin: 'round' + }) + })); + vectorSource.addFeature(feature); + } + + it('tests the canvas renderer', function(done) { + map = createMap('canvas'); + createFeatures(); + expectResemble( + map, 'spec/ol/style/expected/linestring-strokes-canvas.png', + 3.0, done); + }); + }); +}); + +goog.require('goog.dispose'); +goog.require('ol.Feature'); +goog.require('ol.geom.LineString'); +goog.require('ol.Map'); +goog.require('ol.View'); +goog.require('ol.layer.Vector'); +goog.require('ol.source.Vector'); +goog.require('ol.style.Style'); +goog.require('ol.style.Stroke'); diff --git a/test_rendering/spec/ol/style/polygon.test.js b/test_rendering/spec/ol/style/polygon.test.js new file mode 100644 index 0000000000..29f7a64d2c --- /dev/null +++ b/test_rendering/spec/ol/style/polygon.test.js @@ -0,0 +1,200 @@ +goog.provide('ol.test.rendering.style.Polygon'); + +describe('ol.rendering.style.Polygon', function() { + + var target, map, vectorSource; + + function createMap(renderer) { + target = createMapDiv(50, 50); + + vectorSource = new ol.source.Vector(); + vectorLayer = new ol.layer.Vector({ + source: vectorSource + }); + + map = new ol.Map({ + target: target, + renderer: renderer, + layers: [vectorLayer], + view: new ol.View({ + projection: 'EPSG:4326', + center: [0, 0], + resolution: 1 + }) + }); + return map; + } + + describe('different types', function() { + afterEach(function() { + disposeMap(map); + }); + + function createFeatures() { + var fill = new ol.style.Fill({color: 'red'}); + + var feature; + // rectangle + feature = new ol.Feature({ + geometry: new ol.geom.Polygon([ + [[-20, 10], [-20, 20], [-5, 20], [-5, 10], [-20, 10]] + ]) + }); + feature.setStyle(new ol.style.Style({ + fill: fill + })); + vectorSource.addFeature(feature); + + // rectangle with 1 hole + feature = new ol.Feature({ + geometry: new ol.geom.Polygon([ + [[0, 10], [0, 20], [15, 20], [15, 10], [0, 10]], + [[5, 13], [10, 13], [10, 17], [5, 17], [5, 13]] + + ]) + }); + feature.setStyle(new ol.style.Style({ + fill: fill + })); + vectorSource.addFeature(feature); + + // rectangle with 2 holes + feature = new ol.Feature({ + geometry: new ol.geom.Polygon([ + [[-20, -20], [-20, 5], [15, 5], [15, -20], [-20, -20]], + [[-18, -18], [-12, -18], [-12, -12], [-18, -12], [-18, -18]], + [[5, -18], [12, -18], [12, -12], [5, -12], [5, -18]] + + ]) + }); + feature.setStyle(new ol.style.Style({ + fill: fill + })); + vectorSource.addFeature(feature); + } + + it('tests the canvas renderer', function(done) { + map = createMap('canvas'); + createFeatures(); + expectResemble(map, 'spec/ol/style/expected/polygon-types-canvas.png', + IMAGE_TOLERANCE, done); + }); + }); + + describe('z-index', function() { + afterEach(function() { + disposeMap(map); + }); + + function createFeatures() { + var feature; + // rectangle with z-index 2 + feature = new ol.Feature({ + geometry: new ol.geom.Polygon([ + [[-20, 10], [-20, 20], [-0, 20], [-0, 10], [-20, 10]] + ]) + }); + feature.setStyle(new ol.style.Style({ + fill: new ol.style.Fill({color: '#E31E10'}), + zIndex: 2 + })); + vectorSource.addFeature(feature); + + // rectangle with z-index 3 + feature = new ol.Feature({ + geometry: new ol.geom.Polygon([ + [[-15, 5], [-15, 15], [5, 15], [5, 5], [-15, 5]] + ]) + }); + feature.setStyle(new ol.style.Style({ + fill: new ol.style.Fill({color: '#1A5E42'}), + zIndex: 3 + })); + vectorSource.addFeature(feature); + + // rectangle with z-index 1 + feature = new ol.Feature({ + geometry: new ol.geom.Polygon([ + [[-10, 0], [-10, 10], [10, 10], [10, 0], [-10, 0]] + ]) + }); + feature.setStyle(new ol.style.Style({ + fill: new ol.style.Fill({color: '#DEDE21'}), + zIndex: 1 + })); + vectorSource.addFeature(feature); + + } + + it('tests the canvas renderer', function(done) { + map = createMap('canvas'); + createFeatures(); + expectResemble(map, 'spec/ol/style/expected/polygon-zindex-canvas.png', + IMAGE_TOLERANCE, done); + }); + }); + + describe('different fills and strokes', function() { + afterEach(function() { + disposeMap(map); + }); + + function createFeatures() { + var feature; + // rectangle + feature = new ol.Feature({ + geometry: new ol.geom.Polygon([ + [[-20, 10], [-20, 20], [-5, 20], [-5, 10], [-20, 10]] + ]) + }); + feature.setStyle(new ol.style.Style({ + fill: new ol.style.Fill({color: '#9696EB'}), + stroke: new ol.style.Stroke({color: '#9696EB', width: 1}) + })); + vectorSource.addFeature(feature); + + // rectangle with 1 hole + feature = new ol.Feature({ + geometry: new ol.geom.Polygon([ + [[0, 10], [0, 20], [15, 20], [15, 10], [0, 10]] + ]) + }); + feature.setStyle(new ol.style.Style({ + fill: new ol.style.Fill({color: 'rgba(255, 0, 0, 0.1)'}), + stroke: new ol.style.Stroke({color: '#DE213A', width: 3}) + })); + vectorSource.addFeature(feature); + + // rectangle with 2 holes + feature = new ol.Feature({ + geometry: new ol.geom.Polygon([ + [[-20, -20], [-20, 5], [15, 5], [15, -20], [-20, -20]] + ]) + }); + feature.setStyle(new ol.style.Style({ + fill: new ol.style.Fill({color: 'rgba(18, 204, 105, 0.3)'}), + stroke: new ol.style.Stroke({color: '#032E17', width: 2}) + })); + vectorSource.addFeature(feature); + } + + it('tests the canvas renderer', function(done) { + map = createMap('canvas'); + createFeatures(); + expectResemble( + map, 'spec/ol/style/expected/polygon-fill-and-strokes-canvas.png', + IMAGE_TOLERANCE, done); + }); + }); +}); + +goog.require('goog.dispose'); +goog.require('ol.Feature'); +goog.require('ol.geom.Polygon'); +goog.require('ol.Map'); +goog.require('ol.View'); +goog.require('ol.layer.Vector'); +goog.require('ol.source.Vector'); +goog.require('ol.style.Fill'); +goog.require('ol.style.Style'); +goog.require('ol.style.Stroke'); diff --git a/test_rendering/spec/ol/style/regularshape.test.js b/test_rendering/spec/ol/style/regularshape.test.js new file mode 100644 index 0000000000..2eaca4b33e --- /dev/null +++ b/test_rendering/spec/ol/style/regularshape.test.js @@ -0,0 +1,129 @@ +goog.provide('ol.test.rendering.style.RegularShape'); + +describe('ol.rendering.style.RegularShape', function() { + + var target, map, vectorSource; + + function createMap(renderer) { + target = createMapDiv(50, 50); + + vectorSource = new ol.source.Vector(); + vectorLayer = new ol.layer.Vector({ + source: vectorSource + }); + + map = new ol.Map({ + target: target, + renderer: renderer, + layers: [vectorLayer], + view: new ol.View({ + projection: 'EPSG:4326', + center: [0, 0], + resolution: 1 + }) + }); + return map; + } + + describe('#render', function() { + afterEach(function() { + disposeMap(map); + }); + + function createFeatures() { + var stroke = new ol.style.Stroke({color: 'black', width: 2}); + var fill = new ol.style.Fill({color: 'red'}); + + var feature; + feature = new ol.Feature({ + geometry: new ol.geom.Point([-15, 15]) + }); + // square + feature.setStyle(new ol.style.Style({ + image: new ol.style.RegularShape({ + fill: fill, + stroke: stroke, + points: 4, + radius: 10, + angle: Math.PI / 4 + }) + })); + vectorSource.addFeature(feature); + + feature = new ol.Feature({ + geometry: new ol.geom.Point([8, 15]) + }); + // triangle + feature.setStyle(new ol.style.Style({ + image: new ol.style.RegularShape({ + fill: fill, + stroke: stroke, + points: 3, + radius: 10, + rotation: Math.PI / 4, + angle: 0 + }) + })); + vectorSource.addFeature(feature); + + feature = new ol.Feature({ + geometry: new ol.geom.Point([-10, -8]) + }); + // star + feature.setStyle(new ol.style.Style({ + image: new ol.style.RegularShape({ + fill: fill, + stroke: stroke, + points: 5, + radius: 10, + radius2: 4, + angle: 0 + }) + })); + vectorSource.addFeature(feature); + + feature = new ol.Feature({ + geometry: new ol.geom.Point([12, -8]) + }); + // cross + feature.setStyle(new ol.style.Style({ + image: new ol.style.RegularShape({ + fill: fill, + stroke: stroke, + points: 4, + radius: 10, + radius2: 0, + angle: 0 + }) + })); + vectorSource.addFeature(feature); + } + + it('tests the canvas renderer', function(done) { + map = createMap('canvas'); + createFeatures(); + expectResemble(map, 'spec/ol/style/expected/regularshape-canvas.png', + 6.0, done); + }); + + it('tests the WebGL renderer', function(done) { + assertWebGL(); + map = createMap('webgl'); + createFeatures(); + expectResemble(map, 'spec/ol/style/expected/regularshape-webgl.png', + IMAGE_TOLERANCE, done); + }); + }); +}); + +goog.require('goog.dispose'); +goog.require('ol.Feature'); +goog.require('ol.geom.Point'); +goog.require('ol.Map'); +goog.require('ol.View'); +goog.require('ol.layer.Vector'); +goog.require('ol.source.Vector'); +goog.require('ol.style.Fill'); +goog.require('ol.style.RegularShape'); +goog.require('ol.style.Style'); +goog.require('ol.style.Stroke'); From f99196c46684755636168be1859ed51ec683130e Mon Sep 17 00:00:00 2001 From: tsauerwein Date: Thu, 2 Apr 2015 12:55:49 +0200 Subject: [PATCH 3/3] Fix failing test --- test/spec/ol/format/geojsonformat.test.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/spec/ol/format/geojsonformat.test.js b/test/spec/ol/format/geojsonformat.test.js index df3c46342a..6a4906c9b9 100644 --- a/test/spec/ol/format/geojsonformat.test.js +++ b/test/spec/ol/format/geojsonformat.test.js @@ -693,7 +693,8 @@ describe('ol.format.GeoJSON', function() { var newPoint = format.readGeometry(geojson, { featureProjection: 'EPSG:3857' }); - expect(point.getCoordinates()[0]).to.eql(newPoint.getCoordinates()[0]); + expect(point.getCoordinates()[0]).to.roughlyEqual( + newPoint.getCoordinates()[0], 1e-8); expect( Math.abs(point.getCoordinates()[1] - newPoint.getCoordinates()[1])) .to.be.lessThan(0.0000001);