Bläddra i källkod

adding missing files (due to gitignore)

Raanan Weber 7 år sedan
förälder
incheckning
70a5562122

+ 3 - 1
.gitignore

@@ -176,4 +176,6 @@ dist/preview release/package/
 /Viewer/dist/viewer.min.js
 dist/preview release/viewer/babylon.d.ts
 Viewer/dist/viewer.max.js
-Viewer/tests/**/*.js
+Viewer/tests/unit/src/**/*.js
+Viewer/tests/Lib/**/*.js
+Viewer/tests/commons/**/*.js

+ 0 - 127
Viewer/tests/Lib/PixelPixie.ts

@@ -1,127 +0,0 @@
-import { Helper } from "../commons/helper";
-import { AbstractViewer } from "babylonjs-viewer";
-
-
-export class PixelPixieUtils {
-    public static threshold = 3;
-    public static errorRatio = 1;
-
-    public static loadReferenceImage(name: string, callback: (success) => void) {
-        const img = Helper.getReferenceImg();
-        const timeout = setTimeout(() => {
-            img.onload = null;
-
-            if (callback) {
-                callback(false);
-            }
-        }, 1000);
-        img.onload = () => {
-            clearTimeout(timeout);
-            const resultCanvas = Helper.getReferenceCanvas();
-            const resultContext = resultCanvas.getContext("2d");
-            resultCanvas.width = img.width;
-            resultCanvas.height = img.height;
-            resultContext.drawImage(img, 0, 0);
-
-            if (callback) {
-                callback(true);
-            }
-        };
-
-        img.src = "base/assets/referenceImages/" + name + ".png";
-    }
-
-    public static compare(canvas: HTMLCanvasElement, renderData: Uint8Array, stats: { maxDelta: number, differencesCount: number }): boolean {
-        const referenceCanvas = canvas;
-        const width = referenceCanvas.width;
-        const height = referenceCanvas.height;
-        const size = width * height * 4;
-
-        const referenceContext = referenceCanvas.getContext("2d");
-
-        const referenceData = referenceContext.getImageData(0, 0, width, height);
-
-        let maxDelta = 0;
-        let differencesCount = 0;
-        for (let index = 0; index < size; index += 4) {
-            const [r, g, b] = [index, index + 1, index + 2];
-
-            const maxComponentDelta = Math.max(
-                Math.abs(renderData[r] - referenceData.data[r]),
-                Math.abs(renderData[g] - referenceData.data[g]),
-                Math.abs(renderData[b] - referenceData.data[b])
-            );
-
-            maxDelta = Math.max(maxDelta, maxComponentDelta);
-
-            if (maxComponentDelta < this.threshold) {
-                continue;
-            }
-
-            referenceData.data[r] = 255;
-            referenceData.data[g] *= 0.5;
-            referenceData.data[b] *= 0.5;
-            differencesCount++;
-        }
-
-        referenceContext.putImageData(referenceData, 0, 0);
-
-        stats.maxDelta = maxDelta;
-        stats.differencesCount = differencesCount;
-
-        return (differencesCount * 100) / (width * height) > this.errorRatio;
-    }
-
-    public static getRenderData(renderEngine: AbstractViewer): Uint8Array {
-        const width = renderEngine.canvas.width;
-        const height = renderEngine.canvas.height;
-
-        const renderData = renderEngine.engine.readPixels(0, 0, width, height);
-        const numberOfChannelsByLine = width * 4;
-        const halfHeight = height / 2;
-
-        for (let i = 0; i < halfHeight; i++) {
-            for (let j = 0; j < numberOfChannelsByLine; j++) {
-                const currentCell = j + i * numberOfChannelsByLine;
-                const targetLine = height - i - 1;
-                const targetCell = j + targetLine * numberOfChannelsByLine;
-
-                const temp = renderData[currentCell];
-                renderData[currentCell] = renderData[targetCell];
-                renderData[targetCell] = temp;
-            }
-        }
-
-        return renderData;
-    }
-
-    public static evaluate(testName, renderEngine: AbstractViewer, callback: (result: boolean, picture: string, maxDelta: number, differencesCount: number) => void): void {
-        renderEngine.scene.executeWhenReady(() => {
-            // Extra render shouldn't be necessary, this is due to a bug in IE
-
-            //TODO - this should be the viewer's render loop
-            renderEngine.forceRender();
-
-            const renderData = this.getRenderData(renderEngine);
-            Helper.getRenderImg().src = renderEngine.canvas.toDataURL();
-
-            renderEngine.runRenderLoop = false;
-
-            this.loadReferenceImage(testName, (success) => {
-                const referenceCanvas = Helper.getReferenceCanvas();
-                if (success) {
-                    const stats = { maxDelta: 0, differencesCount: 0 };
-                    const different = this.compare(referenceCanvas, renderData, stats);
-                    const resultPicture = referenceCanvas.toDataURL();
-                    Helper.getReferenceImg().onload = null;
-                    Helper.getReferenceImg().src = resultPicture;
-
-                    callback(!different, resultPicture, stats.maxDelta, stats.differencesCount);
-                }
-                else {
-                    callback(false, "Reference image not loaded.", 0, 0);
-                }
-            });
-        });
-    }
-}

+ 39 - 0
Viewer/tests/karma.conf.js

@@ -0,0 +1,39 @@
+module.exports = function (config) {
+    config.set({
+        basePath: '../',
+        captureTimeout: 3e5,
+        browserNoActivityTimeout: 3e5,
+        browserDisconnectTimeout: 3e5,
+        browserDisconnectTolerance: 3,
+        concurrency: 1,
+
+        urlRoot: '/karma/',
+
+        frameworks: ['mocha', 'chai', 'sinon'],
+
+        files: [
+            './tests/unit/build/*.js',
+            { pattern: './tests/**/*', watched: false, included: false, served: true },
+        ],
+        proxies: {
+            '/tests/': '/base/tests/'
+        },
+        client: {
+            mocha: {
+                timeout: 10000
+            }
+        },
+
+        port: 3000,
+        colors: true,
+        autoWatch: false,
+        singleRun: true,
+        browserNoActivityTimeout: 20000,
+
+        // level of logging
+        // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
+        logLevel: config.LOG_INFO,
+
+        browsers: ['PhantomJS']
+    })
+}

+ 61 - 0
Viewer/tests/unit/webpack.config.js

@@ -0,0 +1,61 @@
+const path = require('path');
+const webpack = require('webpack');
+
+module.exports = {
+    entry: {
+        'test': __dirname + '/src/index.ts'
+    },
+    /*output: {
+        libraryTarget: 'var',
+        library: 'ViewerTests',
+        umdNamedDefine: true
+    },*/
+    resolve: {
+        extensions: ['.ts', '.js'],
+        alias: {
+            "babylonjs": __dirname + '/../../../dist/preview release/babylon.max.js',
+            "babylonjs-materials": __dirname + '/../../../dist/preview release/materialsLibrary/babylonjs.materials.js',
+            "babylonjs-loaders": __dirname + '/../../../dist/preview release/loaders/babylonjs.loaders.js',
+            "pep": __dirname + '/../../assets/pep.min.js'
+        }
+    },
+    externals: {
+        // until physics will be integrated in the viewer, ignore cannon
+        cannon: 'CANNON',
+        oimo: 'OIMO',
+        './Oimo': 'OIMO',
+        "earcut": true
+    },
+    devtool: 'source-map',
+    plugins: [
+        new webpack.WatchIgnorePlugin([
+            /\.d\.ts$/
+        ])
+    ],
+    module: {
+        loaders: [{
+            test: /\.tsx?$/,
+            loader: 'ts-loader',
+            exclude: /node_modules/
+        },
+        {
+            test: /\.(html)$/,
+            use: {
+                loader: 'html-loader',
+                options: {
+                    minimize: true
+                }
+            }
+        },
+        {
+            test: /\.(jpe?g|png|ttf|eot|svg|woff(2)?)(\?[a-z0-9=&.]+)?$/,
+            use: 'base64-image-loader?limit=1000&name=[name].[ext]'
+        }]
+    },
+    devServer: {
+        contentBase: path.join(__dirname, "dist"),
+        compress: false,
+        //open: true,
+        port: 9000
+    }
+}

+ 75 - 0
Viewer/tests/validation/integration.js

@@ -0,0 +1,75 @@
+window.__karma__.loaded = function () { };
+
+// Loading tests
+var xhr = new XMLHttpRequest();
+
+xhr.open("GET", "/tests/validation/config.json", true);
+
+xhr.addEventListener("load", function () {
+    if (xhr.status === 200) {
+
+        config = JSON.parse(xhr.responseText);
+
+        describe("Validation Tests", function () {
+            /*before(function (done) {
+                this.timeout(180000);
+                require = null;
+                BABYLONDEVTOOLS.Loader
+                    .require('/tests/validation/validation.js')
+                    .useDist()
+                    .load(function () {
+                        var info = engine.getGlInfo();
+                        console.log("Webgl Version: " + info.version);
+                        console.log("Webgl Vendor: " + info.vendor);
+                        // Reduces error ratio on Embedded Firefox for travis.
+                        if (info.vendor === "VMware, Inc.") {
+                            errorRatio = 5;
+                        }
+
+                        console.log("Webgl Renderer: " + info.renderer);
+                        done();
+                    });
+            });*/
+
+            // Run tests
+            for (let index = 0; index < config.tests.length; index++) {
+                var test = config.tests[index];
+                if (test.onlyVisual || test.excludeFromAutomaticTesting) {
+                    continue;
+                }
+
+                it(test.title, function (done) {
+                    this.timeout(180000);
+
+                    var deferredDone = function (err) {
+                        setTimeout(function () {
+                            done(err);
+                        }, 3000);
+                    }
+
+                    try {
+                        runTest(index, function (result, screenshot) {
+                            try {
+                                expect(result).to.be.true;
+                                deferredDone();
+                            }
+                            catch (e) {
+                                if (screenshot) {
+                                    console.error(screenshot);
+                                }
+                                deferredDone(e);
+                            }
+                        });
+                    }
+                    catch (e) {
+                        deferredDone(e);
+                    }
+                });
+            };
+        });
+
+        window.__karma__.start();
+    }
+}, false);
+
+xhr.send();

+ 94 - 0
Viewer/tests/validation/karma.conf.browserstack.js

@@ -0,0 +1,94 @@
+module.exports = function (config) {
+    'use strict';
+    config.set({
+
+        basePath: '../../',
+        captureTimeout: 3e5,
+        browserNoActivityTimeout: 3e5,
+        browserDisconnectTimeout: 3e5,
+        browserDisconnectTolerance: 3,
+        concurrency: 1,
+
+        urlRoot: '/karma',
+
+        frameworks: ['mocha', 'chai', 'sinon'],
+
+        files: [
+            './dist/preview release/earcut.min.js',
+            './Tools/DevLoader/BabylonLoader.js',
+            './tests/validation/index.css',
+            './tests/validation/integration.js',
+            './favicon.ico',
+            { pattern: 'dist/**/*', watched: false, included: false, served: true },
+            { pattern: 'assets/**/*', watched: false, included: false, served: true },
+            { pattern: 'tests/**/*', watched: false, included: false, served: true },
+            { pattern: 'Playground/scenes/**/*', watched: false, included: false, served: true },
+            { pattern: 'Playground/textures/**/*', watched: false, included: false, served: true },
+            { pattern: 'Playground/sounds/**/*', watched: false, included: false, served: true },
+            { pattern: 'Tools/DevLoader/**/*', watched: false, included: false, served: true },            
+            { pattern: 'Tools/Gulp/config.json', watched: false, included: false, served: true },
+        ],
+        proxies: {
+            '/': '/base/'
+        },
+
+        port: 1338,
+        colors: true,
+        autoWatch: false,
+        singleRun: false,
+
+        // level of logging
+        // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
+        logLevel: config.LOG_INFO,
+
+        browserStack: {
+            project: 'Babylon JS Validation Tests',
+            video: false,
+            debug : 'true',
+            timeout: 1200,
+            build: process.env.TRAVIS_BUILD_NUMBER,
+            username: process.env.BROWSER_STACK_USERNAME,
+            accessKey: process.env.BROWSER_STACK_ACCESS_KEY
+        },
+        customLaunchers: {
+            bs_chrome_win: {
+                base: 'BrowserStack',
+                browser: 'Chrome',
+                browser_version: '63.0',
+                os: 'Windows',
+                os_version: '10'
+            },
+            bs_edge_win: {
+                base: 'BrowserStack',
+                browser: 'Edge',
+                browser_version: '16.0',
+                os: 'Windows',
+                os_version: '10'
+            },
+            bs_firefox_win: {
+                base: 'BrowserStack',
+                browser: 'Firefox',
+                browser_version: '57.0',
+                os: 'Windows',
+                os_version: '10'
+            },
+            bs_chrome_android: {
+                base: 'BrowserStack',
+                os: 'Android',
+                os_version : '8.0',
+                device : 'Google Pixel',
+                real_mobile : 'true'
+            },
+            bs_safari_ios: {
+                base: 'BrowserStack',
+                os: 'ios',
+                os_version : '10.3',
+                device : 'iPhone 7',
+                real_mobile : 'true'
+            }
+        },
+        browsers: ['bs_chrome_android'],
+        reporters: ['dots', 'BrowserStack'],
+        singleRun: true
+    });
+};

+ 40 - 0
Viewer/tests/validation/karma.conf.js

@@ -0,0 +1,40 @@
+module.exports = function (config) {
+    'use strict';
+    config.set({
+
+        basePath: '../../',
+        captureTimeout: 3e5,
+        browserNoActivityTimeout: 3e5,
+        browserDisconnectTimeout: 3e5,
+        browserDisconnectTolerance: 3,
+        concurrency: 1,
+
+        urlRoot: '/karma/',
+
+        frameworks: ['mocha', 'chai', 'sinon'],
+
+        files: [
+            './tests/validation/index.css',
+            '../dist/preview release/viewer/babylon.viewer.max.js',
+            './tests/validation/integration.js',
+            './tests/validation/validation.js',
+            { pattern: './tests/**/*', watched: false, included: false, served: true },
+            { pattern: '../dist/**/*', watched: false, included: false, served: true },
+        ],
+        proxies: {
+            '/tests/': '/base/tests/'
+        },
+
+        port: 3000,
+        colors: true,
+        autoWatch: false,
+        singleRun: false,
+
+        // level of logging
+        // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
+        logLevel: config.LOG_INFO,
+
+        browsers: ['Chrome']
+
+    });
+};

+ 224 - 0
Viewer/tests/validation/validation.js

@@ -0,0 +1,224 @@
+"use strict";
+
+var currentViewer;
+var viewerElement;
+var currentScene;
+var config;
+var justOnce;
+
+var threshold = 25;
+var errorRatio = 2.5;
+
+// Overload the random to make it deterministic
+var seed = 100000,
+    constant = Math.pow(2, 13) + 1,
+    prime = 37,
+    maximum = Math.pow(2, 50);
+
+Math.random = function () {
+    seed *= constant;
+    seed += prime;
+    seed %= maximum;
+
+    return seed / maximum;
+}
+
+function compare(renderData, referenceCanvas) {
+    var width = referenceCanvas.width;
+    var height = referenceCanvas.height;
+    var size = width * height * 4;
+
+    var referenceContext = referenceCanvas.getContext("2d");
+
+    var referenceData = referenceContext.getImageData(0, 0, width, height);
+
+    var differencesCount = 0;
+    for (var index = 0; index < size; index += 4) {
+        if (Math.abs(renderData[index] - referenceData.data[index]) < threshold &&
+            Math.abs(renderData[index + 1] - referenceData.data[index + 1]) < threshold &&
+            Math.abs(renderData[index + 2] - referenceData.data[index + 2]) < threshold) {
+            continue;
+        }
+
+        referenceData.data[index] = 255;
+        referenceData.data[index + 1] *= 0.5;
+        referenceData.data[index + 2] *= 0.5;
+        differencesCount++;
+    }
+
+    referenceContext.putImageData(referenceData, 0, 0);
+
+    return (differencesCount * 100) / (width * height) > errorRatio;
+}
+
+function getRenderData(canvas, engine) {
+    var width = canvas.width;
+    var height = canvas.height;
+
+    var renderData = engine.readPixels(0, 0, width, height);
+    var numberOfChannelsByLine = width * 4;
+    var halfHeight = height / 2;
+
+    for (var i = 0; i < halfHeight; i++) {
+        for (var j = 0; j < numberOfChannelsByLine; j++) {
+            var currentCell = j + i * numberOfChannelsByLine;
+            var targetLine = height - i - 1;
+            var targetCell = j + targetLine * numberOfChannelsByLine;
+
+            var temp = renderData[currentCell];
+            renderData[currentCell] = renderData[targetCell];
+            renderData[targetCell] = temp;
+        }
+    }
+
+    console.log(engine, engine.getRenderingCanvas());
+
+    return renderData;
+}
+
+function saveRenderImage(data, canvas) {
+    var width = canvas.width;
+    var height = canvas.height;
+    var screenshotCanvas = document.createElement('canvas');
+    screenshotCanvas.width = width;
+    screenshotCanvas.height = height;
+    var context = screenshotCanvas.getContext('2d');
+
+    var imageData = context.createImageData(width, height);
+    var castData = imageData.data;
+    castData.set(data);
+    context.putImageData(imageData, 0, 0);
+
+    return screenshotCanvas.toDataURL();
+}
+
+function evaluate(test, resultCanvas, result, renderImage, index, waitRing, done) {
+    seed = 100000;
+    var renderData = getRenderData(currentViewer.canvas, currentViewer.engine);
+    var testRes = true;
+
+    // gl check
+    var gl = currentViewer.engine._gl;
+    if (gl.getError() !== 0) {
+        result.classList.add("failed");
+        result.innerHTML = "×";
+        testRes = false;
+        console.log('%c failed (gl error)', 'color: red');
+    } else {
+
+        // Visual check
+        if (!test.onlyVisual) {
+            if (compare(renderData, resultCanvas)) {
+                result.classList.add("failed");
+                result.innerHTML = "×";
+                testRes = false;
+                console.log('%c failed', 'color: red');
+            } else {
+                result.innerHTML = "✔";
+                testRes = true;
+                console.log('%c validated', 'color: green');
+            }
+        }
+    }
+    waitRing.classList.add("hidden");
+
+    var renderB64 = saveRenderImage(renderData, currentViewer.canvas);
+    renderImage.src = renderB64;
+
+
+
+    done(testRes, renderB64);
+}
+
+function runTest(index, done) {
+    if (index >= config.tests.length) {
+        done(false);
+    }
+
+    var test = config.tests[index];
+    var container = document.createElement("div");
+    container.id = "container#" + index;
+    container.className = "container";
+    document.body.appendChild(container);
+
+    var titleContainer = document.createElement("div");
+    titleContainer.className = "containerTitle";
+    container.appendChild(titleContainer);
+
+    var title = document.createElement("div");
+    title.className = "title";
+    titleContainer.appendChild(title);
+
+    var result = document.createElement("div");
+    result.className = "result";
+    titleContainer.appendChild(result);
+
+    var waitRing = document.createElement("img");
+    waitRing.className = "waitRing";
+    titleContainer.appendChild(waitRing);
+    waitRing.src = "/tests/validation/loading.gif";
+
+    var resultCanvas = document.createElement("canvas");
+    resultCanvas.className = "resultImage";
+    container.appendChild(resultCanvas);
+
+    title.innerHTML = test.title;
+
+    console.log("Running " + test.title);
+
+    var resultContext = resultCanvas.getContext("2d");
+    var img = new Image();
+    img.onload = function () {
+        resultCanvas.width = img.width;
+        resultCanvas.height = img.height;
+        resultContext.drawImage(img, 0, 0);
+    }
+
+    img.src = "/tests/validation/ReferenceImages/" + test.referenceImage;
+
+    var renderImage = new Image();
+    renderImage.className = "renderImage";
+    container.appendChild(renderImage);
+
+    location.href = "#" + container.id;
+
+    //run a single test
+    var configuration = test.configuration || {};
+
+    configuration.engine = configuration.engine || {};
+    configuration.engine.engineOptions = configuration.engine.engineOptions || {};
+    configuration.engine.engineOptions.preserveDrawingBuffer = true;
+
+    // create a new viewer
+    currentViewer && currentViewer.dispose();
+    currentScene = null;
+    console.log("currentViewer", index);
+    currentViewer = new BabylonViewer.DefaultViewer(viewerElement, configuration);
+
+    currentViewer.onModelLoadedObservable.add(() => {
+        console.log("currentViewer", index);
+        setTimeout(() => {
+            evaluate(test, resultCanvas, result, renderImage, index, waitRing, done);
+        }, 1000);
+    });
+}
+
+function init() {
+    BABYLON.SceneLoader.ShowLoadingScreen = false;
+    BABYLON.SceneLoader.ForceFullSceneLoadingForIncremental = true;
+
+    // Draco configuration
+    BABYLON.DracoCompression.Configuration.decoder = {
+        wasmUrl: "../../dist/preview%20release/draco_wasm_wrapper_gltf.js",
+        wasmBinaryUrl: "../../dist/preview%20release/draco_decoder_gltf.wasm",
+        fallbackUrl: "../../dist/preview%20release/draco_decoder_gltf.js"
+    };
+
+    viewerElement = document.createElement("babylon");
+    document.body.appendChild(viewerElement);
+
+    // disable init
+    BabylonViewer.viewerGlobals.disableInit = true;
+}
+
+init();