<commit_before>/*eslint strict: [2, "function"]*/ // IIFE form
/*eslint-disable func-style*/ // So that everything is grouped in one var
(function () {
    "use strict";

    /*global run, exit:true*/ // From bdd.js
    /*global __coverage__*/ // Coverage data

    var safeFunc = Function,
        sources,
        context = (function () {
            /*global global*/ // NodeJS global
            if (typeof global === "object") {
                return global;
            }
            /*global window*/ // Browser global
            if (typeof window !== "undefined") {
                return window;
            }
            return safeFunc("return this;")();
        }()),
        noTimeout = typeof setTimeout === "undefined",

        _resolvePath = function (configuration, relativePath) {
            return configuration.gpfPath
                .split(configuration.pathSeparator)
                .concat(relativePath.split("/"))
                .join(configuration.pathSeparator);
        },

        _processParameters = function (configuration, options) {
            var len = configuration.parameters.length,
                idx,
                value,
                option;
            for (idx = 0; idx < len; ++idx) {
                value = configuration.parameters[idx];
                if (value.charAt(0) === "-") {
                    value = value.substring(1);
                    option = options[value];
                    if (typeof option === "boolean") {
                        options[value] = !option; // Simple switch
                    } else if (typeof option === "function") {
                        option.call(options);
                    }
                } else {
                    options.tests.push(value);
                }
            }
            if (options.perfInfinite) {
                options.perf = true;
            }
        },

        _eval = function (configuration, path, content) {
            try {
                /*jslint evil: true*/
                eval(content); //eslint-disable-line no-eval
                /*jslint evil: false*/
            } catch (e) {
                configuration.log("An error occurred while evaluating: " + path + "\r\n" + e.message);
                configuration.log(e);
                configuration.exit(-1);
            }
        },

        _load = function (configuration, path) {
            _eval(configuration, path, configuration.read(path));
        },

        _requireGpf = function (configuration, path) {
            if (configuration.require) {
                context.gpf = configuration.require(path);
            } else {
                _load(configuration, path);
                if (typeof gpf === "undefined") {
                    configuration.log("GPF was not loaded");
                    configuration.exit(-1);
                }
            }
        },

        _loadGpf = function (configuration, options, verbose) {
            verbose("Using " + options.label + " version");
            if (options.build) {
                _requireGpf(configuration, _resolvePath(configuration, "build/" + options.build + ".js"));
            } else {
                if (!context.gpfSourcesPath) {
                    context.gpfSourcesPath = _resolvePath(configuration, "src/");
                }
                _load(configuration, gpfSourcesPath + "boot.js");
            }
            // Load the list of modules
            var sourcesJson = configuration.read("src/sources.json");
            sources = safeFunc("return " + sourcesJson + ";")();
        },

        _loadBDD = function (configuration, verbose) {
            if (undefined === configuration.run) {
                verbose("Loading BDD...");
                _load(configuration, _resolvePath(configuration, "test/host/bdd.js"));
                verbose("BDD loaded.");
            }
        },

        _loadTest = function (configuration, source) {
            var path = _resolvePath(configuration, "test/" + source + ".js");
            if (configuration.loadTest) {
                configuration.loadTest(path);
            } else {
                var testFileContent = configuration.read(path),
                    modifiedContent = testFileContent.replace(/[^."]assert\((.*)\);/g, function (match, test, offset) {
                        var lines = testFileContent.substring(0, offset).split("\n"),
                            lineNumber = lines.length,
                            pos = lines.pop().length + 1,
                            message = source + ".js@" + lineNumber + ":" + pos + ": " + test
                                .split("\\").join("\\\\")
                                .split("\"").join("\\\"");
                        return match.substring(0, match.length - 2) + ", \"" + message + "\");";
                    });
                _eval(configuration, path, modifiedContent);
            }
        },

        _patchLegacy = function (configuration, verbose, version) {
            // gpf is loaded
            var legacy = JSON.parse(configuration.read(_resolvePath(configuration, "test/legacy/legacy.json")))
                    .filter(function (item) {
                        return item.before > version;
                    }),
                _describes = [],
                _describe = context.describe,
                _it = context.it;
            context.describe = function (label) {
                var issue;
                legacy.every(function (item) {
                    if (item.ignore.some(function (ignore) {
                        return ignore.describe === label && !ignore.it;

                    })) {
                        issue = item.issue;
                        return false;
                    }
                    return true;
                });
                if (issue) {
                    verbose("describe(\"" + label + "\", ...) ignored, see issue #" + issue);
                } else {
                    _describes.unshift(label);
                    _describe.apply(this, arguments);
                    _describes.shift();
                }
            };
            context.it = function (label) {
                var issue;
                legacy.every(function (item) {
                    if (item.ignore.some(function (ignore) {
                        return ignore.describe === _describes[0] && ignore.it === label;

                    })) {
                        issue = item.issue;
                        return false;
                    }
                    return true;
                });
                if (issue) {
                    verbose("it(\"" + label + "\", ...) ignored, see issue #" + issue);
                } else {
                    _it.apply(this, arguments);
                }
            };
        },

        _setupInclude = function (configuration) {
            context.include = function (source) {
              _loadTest(configuration, source);
            }
        },

        _loadTestsFromNames = function (configuration, names, verbose) {
            var len = names.length,
                sourceIdx,
                source;
            for (sourceIdx = 0; sourceIdx < len; ++sourceIdx) {
                source = names[sourceIdx];
                if ((/^legacy(\\|\/)/).exec(source)) {
                    verbose("Legacy detected");
                    _patchLegacy(configuration, verbose, source.substring(7));
                    delete gpf.internals;
                }
                _loadTest(configuration, source);
            }
        },

        _loadTestsFromModules = function (configuration) {
            var len = sources.length,
                sourceIdx,
                source;
            for (sourceIdx = 0; sourceIdx < len; ++sourceIdx) {
                source = sources[sourceIdx];
                if (source.load !== false && source.test !== false) {
                    _loadTest(configuration, source.name);
                }
            }
        },

        _loadTests = function (configuration, options, verbose) {
            try {
                if (options.tests.length) {
                    verbose("Loading specified test files...");
                    _loadTestsFromNames(configuration, options.tests, verbose);
                } else {
                    verbose("Loading all test files...");
                    _loadTestsFromModules(configuration);
                }
            } catch (e) {
                configuration.log("An error occurred while loading tests: " + e.message);
                configuration.log(e);
                configuration.exit(-1);
            }
        },

        _setupConfig = function (configuration) {
            var configFile = JSON.parse(configuration.read(_resolvePath(configuration, "tmp/config.json")));
            context.config = Object.assign({
                httpPort: configFile.serve.httpPort
            }, configuration.config);
        },

        _mean = function (values) {
            var total = 0,
                len = values.length,
                idx;
            for (idx = 0; idx < len; ++idx) {
                total += values[idx];
            }
            return Math.floor(total / len);
        },

        _stdDeviation = function (values) {
            var mean = _mean(values),
                total = 0,
                len = values.length,
                idx,
                diff;
            for (idx = 0; idx < len; ++idx) {
                diff = values[idx] - mean;
                total += diff * diff;
            }
            return Math.floor(Math.sqrt(total / len));
        },

        _pad = function (value, size) {
            var pad = size - value.toString().length;
            if (pad > 0) {
                return new Array(pad).join(" ") + value;
            }
            return value;
        },

        _perfError = function (configuration, data) {
            configuration.log("ERROR during performance test:");
            var property,
                value;
            for (property in data) {
                if (data.hasOwnProperty(property)) {
                    value = data[property];
                    if (property === "exception" && value instanceof Error) {
                        configuration.log("\t" + _pad(property, 10) + ": " + value.message);
                    } else {
                        configuration.log("\t" + _pad(property, 10) + ": " + value.toString());
                    }
                }
            }
        },

        _runBDDPerf = function (configuration, options) {
            var loop = 1,
                maxLoop,
                runWithCallback,
                measures = [];
            if (options.perfInfinite) {
                maxLoop = Math.MAX_SAFE_INTEGER;
            } else {
                maxLoop = 10;
            }
            function callback (type, data) {
                var statistics;
                if (type === "it") {
                    if (!data.result) {
                        _perfError(configuration, data);
                        maxLoop = 0; // Stop
                    }
                } else if (type === "results") {
                    statistics = ["Round ", _pad(loop, 9), ": ", _pad(data.timeSpent, 5), "ms "];
                    if (loop === 1) {
                        statistics.push("(ignored)");
                    } else {
                        measures.push(data.timeSpent);
                        statistics.push("mean: ", _pad(_mean(measures), 5), "ms ",
                            "deviation: ", _pad(_stdDeviation(measures), 5));
                    }
                    configuration.log(statistics.join(""));
                    if (maxLoop < loop) {
                        configuration.log("Mean time: " + _mean(measures) + "ms");
                    } else {
                        ++loop;
                        setTimeout(runWithCallback, 0);
                    }
                }
            }
            runWithCallback = function () {
                run(callback);
            };
            runWithCallback();
        },

        _updloadCoverage = function () {
            var coverageData = JSON.stringify(__coverage__),
                pos = 0,
                length = coverageData.length,
                chunkSize = 4096,
                method = gpf.http.methods.post,
                url = "http://localhost:" + config.httpPort + "/fs/tmp/coverage/reports/coverage."
                    + gpf.host() + ".json";
            function upload () {
                return gpf.http.request({
                    method: method,
                    url: url,
                    data: coverageData.substring(pos, pos + chunkSize)
                })
                    .then(function () {
                        method = gpf.http.methods.put;
                        pos += chunkSize;
                        if (pos < length) {
                            return upload();
                        }
                    });
            }
            return upload();
        },

        _runBDDForCoverage = function (configuration, options, verbose) {
            verbose("Running BDD - coverage");
            run(function (type, data) {
                if (type === "it" && !data.result) {
                    configuration.log("KO: " + data.context.slice(1) + " " + data.label);
                }
                if (type !== "results") {
                    return;
                }
                if (data.fail) {
                    configuration.log("Failed: " + data.fail + ".");
                    configuration.exit(-1);
                }
                verbose("Uploading coverage results...");
                _updloadCoverage()
                    .then(function () {
                        verbose("Coverage results uploaded.");
                        configuration.exit(0);
                    }, function (reason) {
                        configuration.log("Upload failed: " + reason.toString());
                        configuration.exit(-1);
                    });
            });
        },

        _runBDD = function (configuration, options, verbose) {
            exit = configuration.exit; // used by BDD.js
            if (options.perf) {
                verbose("Running BDD - performances");
                _runBDDPerf(configuration, options);
            } else if (options.runCoverage) {
                _runBDDForCoverage(configuration, options, verbose);
            } else {
                verbose("Running BDD");
                run();
            }
        },

        _safeRunBDD = function (configuration, options, verbose) {
            try {
                if (undefined === configuration.run) {
                    _runBDD(configuration, options, verbose);
                } else {
                    configuration.run();
                }
                if (noTimeout) {
                    gpf.handleTimeout();
                }
            } catch (e) {
                configuration.log("An error occurred while running the tests:\r\n" + e.message);
                configuration.exit(-1);
            }
        },

        _loadFlavor = function (configuration, options) {
            // Load the list of modules
            var
                flavorName = options.tests[0].substring(7),
                flavorJson = configuration.read("make/flavor/" + flavorName + ".json"),
                flavor = safeFunc("return " + flavorJson + ";")();
            options.build = "gpf-" + flavorName;
            options.label = "\"" + options.flavor + "\" flavor";
            options.tests = flavor.tests;
        },

        _checkFlavor = function (configuration, options) {
            if (options.tests.length === 1 && options.tests[0].indexOf("flavor:") === 0) {
                _loadFlavor(configuration, options);
            }
        };

    /*
     * Expected members on configuration:
     * - {String[]} parameters command line parameters
     * - {String} gpfPath GPF base path
     * - {String} pathSeparator
     * - {Function} log
     * - {Function} exit
     * - (Function) require
     * - (Function) read  function (filePath) {} reads a file
     * - (Function) [loadTest=undefined] loadTest function (filePath) {} reads a test file
     * - {Function} run When defined, this method is triggered to execute the tests
     */
    context.loadGpfAndTests = function (configuration) {
        var options = {
                build: "",
                label: "source",
                release: function () {
                    this.build = "gpf";
                    this.label = "release";
                },
                debug: function () {
                    this.build = "gpf-debug";
                    this.label = "debug";
                },
                coverage: function () {
                    this.ignoreConsole = true;
                    this.label = "*instrumented* source";
                    this.runCoverage = true;
                    context.global = context;
                    context.gpfSourcesPath = _resolvePath(configuration, "tmp/coverage/instrument/src/");
                },
                verbose: false,
                ignoreConsole: false,
                perf: false,
                perfInfinite: false,
                tests: []
            },
            verbose;
        _processParameters(configuration, options);
        // Define a debug function that outputs when verbose is set
        if (options.verbose) {
            verbose = configuration.log;
        } else {
            verbose = function () {};
        }
        _checkFlavor(configuration, options);
        _loadGpf(configuration, options, verbose);
        _loadBDD(configuration, verbose);
        if (!options.ignoreConsole) {
            verbose("Loading console...");
            _load(configuration, _resolvePath(configuration, "test/host/console.js"));
            verbose("Console loaded.");
        }
        _setupConfig(configuration);
        _setupInclude(configuration);
        _loadTests(configuration, options, verbose);
        _safeRunBDD(configuration, options, verbose);
    };

}());
<commit_msg>Features & include (#304)<commit_after>/*eslint strict: [2, "function"]*/ // IIFE form
/*eslint-disable func-style*/ // So that everything is grouped in one var
(function () {
    "use strict";

    /*global run, exit:true*/ // From bdd.js
    /*global __coverage__*/ // Coverage data

    var safeFunc = Function,
        sources,
        context = (function () {
            /*global global*/ // NodeJS global
            if (typeof global === "object") {
                return global;
            }
            /*global window*/ // Browser global
            if (typeof window !== "undefined") {
                return window;
            }
            return safeFunc("return this;")();
        }()),
        noTimeout = typeof setTimeout === "undefined",

        _resolvePath = function (configuration, relativePath) {
            return configuration.gpfPath
                .split(configuration.pathSeparator)
                .concat(relativePath.split("/"))
                .join(configuration.pathSeparator);
        },

        _processParameters = function (configuration, options) {
            var len = configuration.parameters.length,
                idx,
                value,
                option;
            for (idx = 0; idx < len; ++idx) {
                value = configuration.parameters[idx];
                if (value.charAt(0) === "-") {
                    value = value.substring(1);
                    option = options[value];
                    if (typeof option === "boolean") {
                        options[value] = !option; // Simple switch
                    } else if (typeof option === "function") {
                        option.call(options);
                    }
                } else {
                    options.tests.push(value);
                }
            }
            if (options.perfInfinite) {
                options.perf = true;
            }
        },

        _eval = function (configuration, path, content) {
            try {
                /*jslint evil: true*/
                eval(content); //eslint-disable-line no-eval
                /*jslint evil: false*/
            } catch (e) {
                configuration.log("An error occurred while evaluating: " + path + "\r\n" + e.message);
                configuration.log(e);
                configuration.exit(-1);
            }
        },

        _load = function (configuration, path) {
            _eval(configuration, path, configuration.read(path));
        },

        _requireGpf = function (configuration, path) {
            if (configuration.require) {
                context.gpf = configuration.require(path);
            } else {
                _load(configuration, path);
                if (typeof gpf === "undefined") {
                    configuration.log("GPF was not loaded");
                    configuration.exit(-1);
                }
            }
        },

        _loadGpf = function (configuration, options, verbose) {
            verbose("Using " + options.label + " version");
            if (options.build) {
                _requireGpf(configuration, _resolvePath(configuration, "build/" + options.build + ".js"));
            } else {
                if (!context.gpfSourcesPath) {
                    context.gpfSourcesPath = _resolvePath(configuration, "src/");
                }
                _load(configuration, gpfSourcesPath + "boot.js");
            }
            // Load the list of modules
            var sourcesJson = configuration.read("src/sources.json");
            sources = safeFunc("return " + sourcesJson + ";")();
        },

        _loadBDD = function (configuration, verbose) {
            if (undefined === configuration.run) {
                verbose("Loading BDD...");
                _load(configuration, _resolvePath(configuration, "test/host/bdd.js"));
                verbose("BDD loaded.");
            }
        },

        _loadTest = function (configuration, source) {
            var path = _resolvePath(configuration, "test/" + source + ".js");
            if (configuration.loadTest) {
                configuration.loadTest(path);
            } else {
                var testFileContent = configuration.read(path),
                    modifiedContent = testFileContent.replace(/[^."]assert\((.*)\);/g, function (match, test, offset) {
                        var lines = testFileContent.substring(0, offset).split("\n"),
                            lineNumber = lines.length,
                            pos = lines.pop().length + 1,
                            message = source + ".js@" + lineNumber + ":" + pos + ": " + test
                                .split("\\").join("\\\\")
                                .split("\"").join("\\\"");
                        return match.substring(0, match.length - 2) + ", \"" + message + "\");";
                    });
                _eval(configuration, path, modifiedContent);
            }
        },

        _patchLegacy = function (configuration, verbose, version) {
            // gpf is loaded
            var legacy = JSON.parse(configuration.read(_resolvePath(configuration, "test/legacy/legacy.json")))
                    .filter(function (item) {
                        return item.before > version;
                    }),
                _describes = [],
                _describe = context.describe,
                _it = context.it;
            context.describe = function (label) {
                var issue;
                legacy.every(function (item) {
                    if (item.ignore.some(function (ignore) {
                        return ignore.describe === label && !ignore.it;

                    })) {
                        issue = item.issue;
                        return false;
                    }
                    return true;
                });
                if (issue) {
                    verbose("describe(\"" + label + "\", ...) ignored, see issue #" + issue);
                } else {
                    _describes.unshift(label);
                    _describe.apply(this, arguments);
                    _describes.shift();
                }
            };
            context.it = function (label) {
                var issue;
                legacy.every(function (item) {
                    if (item.ignore.some(function (ignore) {
                        return ignore.describe === _describes[0] && ignore.it === label;

                    })) {
                        issue = item.issue;
                        return false;
                    }
                    return true;
                });
                if (issue) {
                    verbose("it(\"" + label + "\", ...) ignored, see issue #" + issue);
                } else {
                    _it.apply(this, arguments);
                }
            };
        },

        _setupInclude = function (configuration) {
            context.include = function (source) {
                _loadTest(configuration, source);
            };
        },

        _loadTestsFromNames = function (configuration, names, verbose) {
            var len = names.length,
                sourceIdx,
                source;
            for (sourceIdx = 0; sourceIdx < len; ++sourceIdx) {
                source = names[sourceIdx];
                if ((/^legacy(\\|\/)/).exec(source)) {
                    verbose("Legacy detected");
                    _patchLegacy(configuration, verbose, source.substring(7));
                    delete gpf.internals;
                }
                _loadTest(configuration, source);
            }
        },

        _loadTestsFromModules = function (configuration) {
            var len = sources.length,
                sourceIdx,
                source;
            for (sourceIdx = 0; sourceIdx < len; ++sourceIdx) {
                source = sources[sourceIdx];
                if (source.load !== false && source.test !== false) {
                    _loadTest(configuration, source.name);
                }
            }
        },

        _loadTests = function (configuration, options, verbose) {
            try {
                if (options.tests.length) {
                    verbose("Loading specified test files...");
                    _loadTestsFromNames(configuration, options.tests, verbose);
                } else {
                    verbose("Loading all test files...");
                    _loadTestsFromModules(configuration);
                }
            } catch (e) {
                configuration.log("An error occurred while loading tests: " + e.message);
                configuration.log(e);
                configuration.exit(-1);
            }
        },

        _setupConfig = function (configuration) {
            var configFile = JSON.parse(configuration.read(_resolvePath(configuration, "tmp/config.json")));
            context.config = Object.assign({
                httpPort: configFile.serve.httpPort
            }, configuration.config);
            _load(configuration, _resolvePath(configuration, "test/host/features.js"));
            _setupInclude(configuration);
        },

        _mean = function (values) {
            var total = 0,
                len = values.length,
                idx;
            for (idx = 0; idx < len; ++idx) {
                total += values[idx];
            }
            return Math.floor(total / len);
        },

        _stdDeviation = function (values) {
            var mean = _mean(values),
                total = 0,
                len = values.length,
                idx,
                diff;
            for (idx = 0; idx < len; ++idx) {
                diff = values[idx] - mean;
                total += diff * diff;
            }
            return Math.floor(Math.sqrt(total / len));
        },

        _pad = function (value, size) {
            var pad = size - value.toString().length;
            if (pad > 0) {
                return new Array(pad).join(" ") + value;
            }
            return value;
        },

        _perfError = function (configuration, data) {
            configuration.log("ERROR during performance test:");
            var property,
                value;
            for (property in data) {
                if (data.hasOwnProperty(property)) {
                    value = data[property];
                    if (property === "exception" && value instanceof Error) {
                        configuration.log("\t" + _pad(property, 10) + ": " + value.message);
                    } else {
                        configuration.log("\t" + _pad(property, 10) + ": " + value.toString());
                    }
                }
            }
        },

        _runBDDPerf = function (configuration, options) {
            var loop = 1,
                maxLoop,
                runWithCallback,
                measures = [];
            if (options.perfInfinite) {
                maxLoop = Math.MAX_SAFE_INTEGER;
            } else {
                maxLoop = 10;
            }
            function callback (type, data) {
                var statistics;
                if (type === "it") {
                    if (!data.result) {
                        _perfError(configuration, data);
                        maxLoop = 0; // Stop
                    }
                } else if (type === "results") {
                    statistics = ["Round ", _pad(loop, 9), ": ", _pad(data.timeSpent, 5), "ms "];
                    if (loop === 1) {
                        statistics.push("(ignored)");
                    } else {
                        measures.push(data.timeSpent);
                        statistics.push("mean: ", _pad(_mean(measures), 5), "ms ",
                            "deviation: ", _pad(_stdDeviation(measures), 5));
                    }
                    configuration.log(statistics.join(""));
                    if (maxLoop < loop) {
                        configuration.log("Mean time: " + _mean(measures) + "ms");
                    } else {
                        ++loop;
                        setTimeout(runWithCallback, 0);
                    }
                }
            }
            runWithCallback = function () {
                run(callback);
            };
            runWithCallback();
        },

        _updloadCoverage = function () {
            var coverageData = JSON.stringify(__coverage__),
                pos = 0,
                length = coverageData.length,
                chunkSize = 4096,
                method = gpf.http.methods.post,
                url = "http://localhost:" + config.httpPort + "/fs/tmp/coverage/reports/coverage."
                    + gpf.host() + ".json";
            function upload () {
                return gpf.http.request({
                    method: method,
                    url: url,
                    data: coverageData.substring(pos, pos + chunkSize)
                })
                    .then(function () {
                        method = gpf.http.methods.put;
                        pos += chunkSize;
                        if (pos < length) {
                            return upload();
                        }
                    });
            }
            return upload();
        },

        _runBDDForCoverage = function (configuration, options, verbose) {
            verbose("Running BDD - coverage");
            run(function (type, data) {
                if (type === "it" && !data.result) {
                    configuration.log("KO: " + data.context.slice(1) + " " + data.label);
                }
                if (type !== "results") {
                    return;
                }
                if (data.fail) {
                    configuration.log("Failed: " + data.fail + ".");
                    configuration.exit(-1);
                }
                verbose("Uploading coverage results...");
                _updloadCoverage()
                    .then(function () {
                        verbose("Coverage results uploaded.");
                        configuration.exit(0);
                    }, function (reason) {
                        configuration.log("Upload failed: " + reason.toString());
                        configuration.exit(-1);
                    });
            });
        },

        _runBDD = function (configuration, options, verbose) {
            exit = configuration.exit; // used by BDD.js
            if (options.perf) {
                verbose("Running BDD - performances");
                _runBDDPerf(configuration, options);
            } else if (options.runCoverage) {
                _runBDDForCoverage(configuration, options, verbose);
            } else {
                verbose("Running BDD");
                run();
            }
        },

        _safeRunBDD = function (configuration, options, verbose) {
            try {
                if (undefined === configuration.run) {
                    _runBDD(configuration, options, verbose);
                } else {
                    configuration.run();
                }
                if (noTimeout) {
                    gpf.handleTimeout();
                }
            } catch (e) {
                configuration.log("An error occurred while running the tests:\r\n" + e.message);
                configuration.exit(-1);
            }
        },

        _loadFlavor = function (configuration, options) {
            // Load the list of modules
            var
                flavorName = options.tests[0].substring(7),
                flavorJson = configuration.read("make/flavor/" + flavorName + ".json"),
                flavor = safeFunc("return " + flavorJson + ";")();
            options.build = "gpf-" + flavorName;
            options.label = "\"" + options.flavor + "\" flavor";
            options.tests = flavor.tests;
        },

        _checkFlavor = function (configuration, options) {
            if (options.tests.length === 1 && options.tests[0].indexOf("flavor:") === 0) {
                _loadFlavor(configuration, options);
            }
        };

    /*
     * Expected members on configuration:
     * - {String[]} parameters command line parameters
     * - {String} gpfPath GPF base path
     * - {String} pathSeparator
     * - {Function} log
     * - {Function} exit
     * - (Function) require
     * - (Function) read  function (filePath) {} reads a file
     * - (Function) [loadTest=undefined] loadTest function (filePath) {} reads a test file
     * - {Function} run When defined, this method is triggered to execute the tests
     */
    context.loadGpfAndTests = function (configuration) {
        var options = {
                build: "",
                label: "source",
                release: function () {
                    this.build = "gpf";
                    this.label = "release";
                },
                debug: function () {
                    this.build = "gpf-debug";
                    this.label = "debug";
                },
                coverage: function () {
                    this.ignoreConsole = true;
                    this.label = "*instrumented* source";
                    this.runCoverage = true;
                    context.global = context;
                    context.gpfSourcesPath = _resolvePath(configuration, "tmp/coverage/instrument/src/");
                },
                verbose: false,
                ignoreConsole: false,
                perf: false,
                perfInfinite: false,
                tests: []
            },
            verbose;
        _processParameters(configuration, options);
        // Define a debug function that outputs when verbose is set
        if (options.verbose) {
            verbose = configuration.log;
        } else {
            verbose = function () {};
        }
        _checkFlavor(configuration, options);
        _loadGpf(configuration, options, verbose);
        _loadBDD(configuration, verbose);
        if (!options.ignoreConsole) {
            verbose("Loading console...");
            _load(configuration, _resolvePath(configuration, "test/host/console.js"));
            verbose("Console loaded.");
        }
        _setupConfig(configuration);
        _loadTests(configuration, options, verbose);
        _safeRunBDD(configuration, options, verbose);
    };

}());
<|endoftext|>


<commit_before>/*!
 * integration test for all components
 */

var Assert = require('assert');
var Vows = require('vows');

var Parser = require('../lib/parser');
var Environment = require('../lib/environment');
var interpreter = require('../lib/interpreter').createInterpreter(
  Environment.createEnvironment()
);

function exec(code) {
  var ast = Parser.parse(code);
  return interpreter.eval(ast);
}

function execAssert(code, result) {
  var res = exec(code);
  Assert.strictEqual(res, result);
}

Vows.describe('test all components of interpreter').addBatch({
    'some simple calclulations' : {

      '3 + 2 = 5' : function () {
        execAssert('(plus 3 2)', 5);
      },

      '10 + 2 - 5 = 7' : function () {
        var test = '(minus (plus 10 2) 5)';
        execAssert(test, 7)
      },

      '1 + 2 + 3 + 4 + 5 = 15' : function () {
        var test = '(plus 1 2 3 4 5)';
        execAssert(test, 15);
      },

      '2 * 2 + 4 * 4 = 20' : function () {
        var test = '(plus (multiply 2 2) (multiply 4 4))';
        execAssert(test, 20);
      }
    },

    'test boolean expressions' : {
      '1 == 1' : function () {
        var test = '(eq? 1 1)';
        execAssert(test, true);
      },

      '1 === 2' : function () {
        var test = '(eq? 1 2)';
        execAssert(test, false);
      }
    },

    'test conditional expressions' : {

      'if (1 === 1)' : function () {
        var test = '(if (eq? 1 1) #t #f)';
        execAssert(test, true);
      },

      'if (1 === 2)' : function () {
        var test = '(if (eq? 1 2) #t #f)';
        execAssert(test, false);
      },

      'cond without else 1' : function () {
        var test = '(cond ((eq? 1 2) "a") ((eq? 2 2) "b")';
        execAssert(test, 'b');
      },

      'cond without else 2' : function () {
        var test = '(cond ((eq? 1 1) "a") ((eq? 2 2) "b")';
        execAssert(test, 'a');
      },

      'cond with else 1' : function () {
        var test = '(cond (#f "should not happen") (else "test"))';
        execAssert(test, 'test');
      },

      'cond with else 2' : function () {
        var test = '(cond (#f "a") (#f "b") (#t "c") (else "test"))';
        execAssert(test, 'c');
      }

    },

    'test lambda expressions' : {

      'simple lambda' : function () {
        var test = '((lambda (n) (multiply n 10)) 3)';
        execAssert(test, 30);
      },

      'multiple argument lambda' : function () {
        var test = '((lambda (a b c) (plus a b c)) 1 2 3)';
        execAssert(test, 6);
      },

      'define lambda and call it' : function () {
        var test = '(define timesten (lambda (n) (multiply n 10)))';
        exec(test);
        execAssert('(timesten 5)', 50);
      }

    },

    'test closures' : {

      'simple closure' : function () {
        exec('(define multiplier 10)');
        execAssert('((lambda (x) (multiply x multiplier)) 10)', 100);
      },

      'simple closure' : function () {
        exec('(define multipair (cons 2 5))');
        execAssert('((lambda (x) (multiply (car multipair) (cdr multipair) x)) 10)', 100);
      }

    }

  }).export(module);
<commit_msg>Integration test: rename eq? to equals<commit_after>/*!
 * integration test for all components
 */

var Assert = require('assert');
var Vows = require('vows');

var Parser = require('../lib/parser');
var Environment = require('../lib/environment');
var interpreter = require('../lib/interpreter').createInterpreter(
  Environment.createEnvironment()
);

function exec(code) {
  var ast = Parser.parse(code);
  return interpreter.eval(ast);
}

function execAssert(code, result) {
  var res = exec(code);
  Assert.strictEqual(res, result);
}

Vows.describe('test all components of interpreter').addBatch({
    'some simple calclulations' : {

      '3 + 2 = 5' : function () {
        execAssert('(plus 3 2)', 5);
      },

      '10 + 2 - 5 = 7' : function () {
        var test = '(minus (plus 10 2) 5)';
        execAssert(test, 7)
      },

      '1 + 2 + 3 + 4 + 5 = 15' : function () {
        var test = '(plus 1 2 3 4 5)';
        execAssert(test, 15);
      },

      '2 * 2 + 4 * 4 = 20' : function () {
        var test = '(plus (multiply 2 2) (multiply 4 4))';
        execAssert(test, 20);
      }
    },

    'test boolean expressions' : {
      '1 == 1' : function () {
        var test = '(equals 1 1)';
        execAssert(test, true);
      },

      '1 === 2' : function () {
        var test = '(equals 1 2)';
        execAssert(test, false);
      }
    },

    'test conditional expressions' : {

      'if (1 === 1)' : function () {
        var test = '(if (equals 1 1) #t #f)';
        execAssert(test, true);
      },

      'if (1 === 2)' : function () {
        var test = '(if (equals 1 2) #t #f)';
        execAssert(test, false);
      },

      'cond without else 1' : function () {
        var test = '(cond ((equals 1 2) "a") ((equals 2 2) "b")';
        execAssert(test, 'b');
      },

      'cond without else 2' : function () {
        var test = '(cond ((equals 1 1) "a") ((equals 2 2) "b")';
        execAssert(test, 'a');
      },

      'cond with else 1' : function () {
        var test = '(cond (#f "should not happen") (else "test"))';
        execAssert(test, 'test');
      },

      'cond with else 2' : function () {
        var test = '(cond (#f "a") (#f "b") (#t "c") (else "test"))';
        execAssert(test, 'c');
      }

    },

    'test lambda expressions' : {

      'simple lambda' : function () {
        var test = '((lambda (n) (multiply n 10)) 3)';
        execAssert(test, 30);
      },

      'multiple argument lambda' : function () {
        var test = '((lambda (a b c) (plus a b c)) 1 2 3)';
        execAssert(test, 6);
      },

      'define lambda and call it' : function () {
        var test = '(define timesten (lambda (n) (multiply n 10)))';
        exec(test);
        execAssert('(timesten 5)', 50);
      }

    },

    'test closures' : {

      'simple closure' : function () {
        exec('(define multiplier 10)');
        execAssert('((lambda (x) (multiply x multiplier)) 10)', 100);
      },

      'simple closure' : function () {
        exec('(define multipair (cons 2 5))');
        execAssert('((lambda (x) (multiply (car multipair) (cdr multipair) x)) 10)', 100);
      }

    }

  }).export(module);
<|endoftext|>


<commit_before>'use strict';

var assert, path, fs, modulePath;

assert = require('chai').assert;
path = require('path');
fs = require('fs');

modulePath = '../src';

suite('integration:', function () {
    var log;

    setup(function () {
        log = {};
    });

    teardown(function () {
        log = undefined;
    });

    test('require does not throw', function () {
        assert.doesNotThrow(function () {
            require(modulePath);
        });
    });

    test('require returns object', function () {
        assert.isObject(require(modulePath));
    });

    suite('require:', function () {
        var bfj;

        setup(function () {
            bfj = require(modulePath);
        });

        teardown(function () {
            bfj = undefined;
        });

        test('walk function is exported', function () {
            assert.isFunction(bfj.walk);
        });

        test('walk expects one argument', function () {
            assert.lengthOf(bfj.walk, 1);
        });

        test('parse function is exported', function () {
            assert.isFunction(bfj.parse);
        });

        test('parse expects two arguments', function () {
            assert.lengthOf(bfj.parse, 2);
        });

        test('read function is exported', function () {
            assert.isFunction(bfj.read);
        });

        test('read expects two arguments', function () {
            assert.lengthOf(bfj.read, 2);
        });

        test('events are exported', function () {
            assert.deepEqual(bfj.events, require('../src/events'));
        });

        suite('read object:', function () {
            var failed, file, result, error;

            setup(function (done) {
                failed = false;
                file = path.join(__dirname, 'data.json');
                fs.writeFileSync(file, JSON.stringify({
                    foo: [ 'b', 'a', 'r' ],
                    baz: null,
                    qux: 3.14159265359e42
                }, null, '\t'));
                bfj.read(file)
                    .then(function (r) {
                        result = r;
                        done();
                    })
                    .catch(function (e) {
                        failed = true;
                        error = e;
                        done();
                    });
            });

            teardown(function () {
                fs.unlinkSync(file);
                failed = file = result = error = undefined;
            });

            test('result was correct', function () {
                assert.isFalse(failed);
                assert.isUndefined(error);
                assert.isObject(result);
                assert.lengthOf(Object.keys(result), 3);
                assert.isArray(result.foo);
                assert.lengthOf(result.foo, 3);
                assert.strictEqual(result.foo[0], 'b');
                assert.strictEqual(result.foo[1], 'a');
                assert.strictEqual(result.foo[2], 'r');
                assert.isNull(result.baz);
                assert.strictEqual(result.qux, 3.14159265359e42);
            });
        });

        suite('read value:', function () {
            var failed, file, result, error;

            setup(function (done) {
                failed = false;
                file = path.join(__dirname, 'data.json');
                fs.writeFileSync(file, '"foo"');
                bfj.read(file)
                    .then(function (r) {
                        result = r;
                        done();
                    })
                    .catch(function (e) {
                        failed = true;
                        error = e;
                        done();
                    });
            });

            teardown(function () {
                fs.unlinkSync(file);
                failed = file = result = error = undefined;
            });

            test('result was correct', function () {
                assert.isFalse(failed);
                assert.isUndefined(error);
                assert.strictEqual(result, 'foo');
            });
        });

        suite('read error:', function () {
            var failed, file, result, error;

            setup(function (done) {
                failed = false;
                file = path.join(__dirname, 'data.json');
                fs.writeFileSync(file, '"foo" "bar"');
                bfj.read(file)
                    .then(function (r) {
                        result = r;
                        done();
                    })
                    .catch(function (e) {
                        failed = true;
                        error = e;
                        done();
                    });
            });

            teardown(function () {
                fs.unlinkSync(file);
                failed = file = result = error = undefined;
            });

            test('result was correct', function () {
                assert.isTrue(failed);
                assert.isUndefined(result);
                assert.instanceOf(error, Error);
            });
        });
    });
});

<commit_msg>Integration test for write.<commit_after>'use strict';

var assert, path, fs, modulePath;

assert = require('chai').assert;
path = require('path');
fs = require('fs');

modulePath = '../src';

suite('integration:', function () {
    var log;

    setup(function () {
        log = {};
    });

    teardown(function () {
        log = undefined;
    });

    test('require does not throw', function () {
        assert.doesNotThrow(function () {
            require(modulePath);
        });
    });

    test('require returns object', function () {
        assert.isObject(require(modulePath));
    });

    suite('require:', function () {
        var bfj;

        setup(function () {
            bfj = require(modulePath);
        });

        teardown(function () {
            bfj = undefined;
        });

        test('walk function is exported', function () {
            assert.isFunction(bfj.walk);
        });

        test('walk expects one argument', function () {
            assert.lengthOf(bfj.walk, 1);
        });

        test('parse function is exported', function () {
            assert.isFunction(bfj.parse);
        });

        test('parse expects two arguments', function () {
            assert.lengthOf(bfj.parse, 2);
        });

        test('read function is exported', function () {
            assert.isFunction(bfj.read);
        });

        test('read expects two arguments', function () {
            assert.lengthOf(bfj.read, 2);
        });

        test('eventify function is exported', function () {
            assert.isFunction(bfj.eventify);
        });

        test('eventify expects two arguments', function () {
            assert.lengthOf(bfj.eventify, 2);
        });

        test('streamify function is exported', function () {
            assert.isFunction(bfj.streamify);
        });

        test('streamify expects two arguments', function () {
            assert.lengthOf(bfj.streamify, 2);
        });

        test('stringify function is exported', function () {
            assert.isFunction(bfj.stringify);
        });

        test('stringify expects two arguments', function () {
            assert.lengthOf(bfj.stringify, 2);
        });

        test('write function is exported', function () {
            assert.isFunction(bfj.write);
        });

        test('write expects two arguments', function () {
            assert.lengthOf(bfj.write, 3);
        });

        test('events are exported', function () {
            assert.deepEqual(bfj.events, require('../src/events'));
        });

        suite('read object:', function () {
            var failed, file, result, error;

            setup(function (done) {
                failed = false;
                file = path.join(__dirname, 'data.json');
                fs.writeFileSync(file, JSON.stringify({
                    foo: [ 'b', 'a', 'r' ],
                    baz: null,
                    qux: 3.14159265359e42
                }, null, '\t'));
                bfj.read(file)
                    .then(function (r) {
                        result = r;
                        done();
                    })
                    .catch(function (e) {
                        failed = true;
                        error = e;
                        done();
                    });
            });

            teardown(function () {
                fs.unlinkSync(file);
                failed = file = result = error = undefined;
            });

            test('result was correct', function () {
                assert.isFalse(failed);
                assert.isUndefined(error);
                assert.isObject(result);
                assert.lengthOf(Object.keys(result), 3);
                assert.isArray(result.foo);
                assert.lengthOf(result.foo, 3);
                assert.strictEqual(result.foo[0], 'b');
                assert.strictEqual(result.foo[1], 'a');
                assert.strictEqual(result.foo[2], 'r');
                assert.isNull(result.baz);
                assert.strictEqual(result.qux, 3.14159265359e42);
            });
        });

        suite('read value:', function () {
            var failed, file, result, error;

            setup(function (done) {
                failed = false;
                file = path.join(__dirname, 'data.json');
                fs.writeFileSync(file, '"foo"');
                bfj.read(file)
                    .then(function (r) {
                        result = r;
                        done();
                    })
                    .catch(function (e) {
                        failed = true;
                        error = e;
                        done();
                    });
            });

            teardown(function () {
                fs.unlinkSync(file);
                failed = file = result = error = undefined;
            });

            test('result was correct', function () {
                assert.isFalse(failed);
                assert.isUndefined(error);
                assert.strictEqual(result, 'foo');
            });
        });

        suite('read error:', function () {
            var failed, file, result, error;

            setup(function (done) {
                failed = false;
                file = path.join(__dirname, 'data.json');
                fs.writeFileSync(file, '"foo" "bar"');
                bfj.read(file)
                    .then(function (r) {
                        result = r;
                        done();
                    })
                    .catch(function (e) {
                        failed = true;
                        error = e;
                        done();
                    });
            });

            teardown(function () {
                fs.unlinkSync(file);
                failed = file = result = error = undefined;
            });

            test('result was correct', function () {
                assert.isTrue(failed);
                assert.isUndefined(result);
                assert.instanceOf(error, Error);
            });
        });

        suite('write object:', function () {
            var failed, file, result;

            setup(function (done) {
                failed = false;
                file = path.join(__dirname, 'data.json');
                bfj.write(
                    file,
                    { foo: [ 'b', 'a', 'r' ], baz: null, qux: 3.14159265359e42 }
                ).on('finish', function () {
                    result = fs.readFileSync(file, { encoding: 'utf8' });
                    done();
                });
            });

            teardown(function () {
                fs.unlinkSync(file);
                failed = file = result = undefined;
            });

            test('result was correct', function () {
                assert.strictEqual(result, '{"foo":["b","a","r"],"baz":null,"qux":3.14159265359e+42}');
            });
        });
    });
});

<|endoftext|>


<commit_before>const { test } = require('ava')

test('', (t) => {})
<commit_msg>bump version<commit_after>const { test } = require('ava')

test('', (t) => t.truthy(42))
<|endoftext|>


<commit_before>import { async, defer, _, lazy_require } from 'azk';

var AVAILABLE_PROVIDERS = ["docker", "dockerfile", "rocket"];
var default_tag      = "latest";
var default_provider = "docker";

lazy_require(this, {
  DImage() {
    return require('azk/docker').Image;
  },

  docker() {
    return require('azk/docker').default;
  }
});

export class Image {
  constructor(image) {

    // 1. only a string, will be deprecated. i.e.: 'azukiapp/azktcl:0.0.2'
    if (_.isString(image)) {
      this.isDeprecated = true;
      this.name = image;
      return null;
    }

    this.provider = image;

    if (!image.repository && this.provider) {
      // 2. i.e.: { dockerfile: 'azukiapp/azktcl' }
      this.name = image[this.provider];
    } else {
      // 3. i.e.: { provider: 'dockerfile', repository: 'azukiapp/azktcl' }
      this.repository = image.repository;
      this.tag        = image.tag || default_tag;
    }
  }

  check() {
    return defer((_resolve, _reject, notify) => {
      notify({ type: "action", context: "image", action: "check_image" });
      return docker.findImage(this.name);
    });
  }

  pull(stdout) {
    return async(this, function* (notify) {
      var image = yield this.check();
      if (image == null) {
        notify({ type: "action", context: "image", action: "pull_image", data: this });
        image = yield docker.pull(this.repository, this.tag, _.isObject(stdout) ? stdout : null);
      }
      return image;
    });
  }

  set name(value) {
    var imageParsed = DImage.parseRepositoryTag(value);
    this.repository = imageParsed.repository;
    this.tag        = imageParsed.tag      || default_tag;
    this.provider   = imageParsed.provider || default_provider;
  }

  get name() {
    return `${this.repository}:${this.tag}`;
  }

  get full_name() {
    return `{ ${this.provider}: "${this.repository}:${this.tag}" }`;
  }

  set provider(image) {
    if (image.provider && _.contains(AVAILABLE_PROVIDERS, image.provider)) {
      this._provider = image.provider;
    } else {
      var provider = _.find(_.keys(image), function(key) {
        if (_.contains(AVAILABLE_PROVIDERS, key)) {
          return key;
        };
      });

      this._provider = provider || default_provider;
    }
  }

  get provider() {
    return this._provider;
  }
}
<commit_msg>[#204 image_azkfile] Including some comments<commit_after>import { async, defer, _, lazy_require } from 'azk';

var AVAILABLE_PROVIDERS = ["docker", "dockerfile", "rocket"];
var default_tag      = "latest";
var default_provider = "docker";

lazy_require(this, {
  DImage() {
    return require('azk/docker').Image;
  },

  docker() {
    return require('azk/docker').default;
  }
});

export class Image {
  constructor(image) {

    // 1. only a string, will be deprecated. i.e.: 'azukiapp/azktcl:0.0.2'
    if (_.isString(image)) {
      this.isDeprecated = true;
      this.name = image;
      return null;
    }

    this.provider = image;

    if (!image.repository && this.provider) {
      // 2. i.e.: { dockerfile: 'azukiapp/azktcl' }
      this.name = image[this.provider];
    } else {
      // 3. i.e.: { provider: 'dockerfile', repository: 'azukiapp/azktcl' }
      this.repository = image.repository;
      this.tag        = image.tag || default_tag;
    }
  }

  check() {
    return defer((_resolve, _reject, notify) => {
      notify({ type: "action", context: "image", action: "check_image" });
      return docker.findImage(this.name);
    });
  }

  pull(stdout) {
    return async(this, function* (notify) {
      var image = yield this.check();
      if (image == null) {
        notify({ type: "action", context: "image", action: "pull_image", data: this });
        image = yield docker.pull(this.repository, this.tag, _.isObject(stdout) ? stdout : null);
      }
      return image;
    });
  }

  set name(value) {
    var imageParsed = DImage.parseRepositoryTag(value);
    this.repository = imageParsed.repository;
    this.tag        = imageParsed.tag      || default_tag;
    this.provider   = imageParsed.provider || default_provider;
  }

  get name() {
    return `${this.repository}:${this.tag}`;
  }

  get full_name() {
    return `{ ${this.provider}: "${this.repository}:${this.tag}" }`;
  }

  set provider(image) {
    if (image.provider && _.contains(AVAILABLE_PROVIDERS, image.provider)) {
      // { provider: 'dockerfile', repository: 'azukiapp/azktcl' }
      this._provider = image.provider;
    } else {
      // { docker: 'azukiapp/azktcl' }
      var provider = _.find(_.keys(image), function(key) {
        if (_.contains(AVAILABLE_PROVIDERS, key)) {
          return key;
        }
      });

      this._provider = provider || default_provider;
    }
  }

  get provider() {
    return this._provider;
  }
}
<|endoftext|>


<commit_before>/**
 * Staballoy is created by Rene Pot (2017)
 * Version 0.2.4 -- 2017-12-05
 * It extends alloy to add reactive components to Titanium.
 * The latest version can be found at Github: https://github.com/topener/staballoy
 */

var requiredControllers = {};
var activeControllers = [];
var subscribers = [];
var vars = {};
var currentlyFocussed = false;

/**
 * Alloy.createController override
 */
Alloy.createController = function(name, args) {
    var args = args || {};

    if (Alloy.CFG.debug) console.log('creating controller in staballoy: ', name, args);

    if (!requiredControllers[name]){
        requiredControllers[name] = require("/alloy/controllers/" + name);
    }
    var controllerGuid = guid();
    args.staballoy = {setVar: setVar, getVar: getVar, guid: controllerGuid};
    args.subscribe = subscribe;
    var controller = new (requiredControllers[name])(args);
    controller.getView().guid = controllerGuid;

    // only parse through all subscribable components
    if (isSubscribable(controller.getView().apiName)){
        if (controller.getView().apiName == 'Ti.UI.iOS.NavigationWindow'){
            parseChildren([controller.getView().window], controller);
        } else {
            parseChildren(controller.getView().children, controller);
        }
        if (controller.getView().staballoy){
            parseSubscriptions(controller.getView(), controller);
        }
        activeControllers.push({controller: controller, guid: controllerGuid});
        controller.getView().addEventListener('focus', handleFocus);
        controller.getView().addEventListener('close', handleClose);

        if (!currentlyFocussed){
            currentlyFocussed = controllerGuid;
        }
    }
    return controller;
};

/**
 * look through all UI elements and find those that need subscribing
 */
function parseChildren(children, controller){
    _.each(children, function(child){
        if (child.children && child.children.length > 0){
            parseChildren(child.children, controller);
            if (child.staballoy){
                parseSubscriptions(child, controller);
            }
        } else if (child.sections && child.sections.length > 0){
            parseChildren(child.sections, controller);
        }

        if (child.staballoy){
            parseSubscriptions(child, controller);
        }
    });
}

/**
 * parse through all subscriptions of the component
 */
function parseSubscriptions(elem, controller){
    if (!elem.staballoy.subscriptions || elem.staballoy.subscriptions.length == 0) return;
    _.each(elem.staballoy.subscriptions, function(attribute, variable){

        // create a subscription model
        var data = {"var": variable,  "component": elem, "attribute": attribute, "window": controller.args.staballoy.guid};
        if (elem.staballoy.logicFunction){
            if (typeof elem.staballoy.logicFunction == 'string'){

                if (controller[elem.staballoy.logicFunction] && typeof controller[elem.staballoy.logicFunction] == 'function'){
                    data.logicFunction = controller[elem.staballoy.logicFunction];
                }
            } else {
                data.logicFunction = elem.staballoy.logicFunction;
            }
        }

        if (attribute === 'value'){
          elem.addEventListener('change', valueChange);
          data.valueListener = true;
        }

        trigger(data);
        subscribers.push(data);
    });
}

function valueChange(e) {
    if (e.source && e.source.staballoy) {
        _.each(e.source.staballoy.subscriptions, function(attribute, variable) {
            if (attribute === 'value') {
                setVar(variable, e.source.value);
            }
        });
    }
}

/**
 * The in-controller exposed subscribe method
 */
function subscribe(args){

    if (typeof args.window == 'string' && getWindowIndexById(args.window) > -1){
        args.window = activeControllers[getWindowIndexById(args.window)].controller;
    }

    if (!isSubscribable(args.window.getView().apiName)){
        return console.error('subscription not possible without context window');
    }

    if (!args.subscriptions || args.subscriptions.length == 0) return;

    args.component.staballoy = {subscriptions: args.subscriptions, logicFunction: args.logicFunction};
    parseSubscriptions(args.component, args.window);

}

/**
 * handle focus and store which is focussed last
 */
function handleFocus(e){
    currentlyFocussed = e.source.guid;
}

function getWindowIndexById(guid){
    return _.findIndex(activeControllers, function(c){
        return c.guid == guid;
    });
}

/**
 * Callback method on the close event listener
 */
function handleClose(e){
    var index = getWindowIndexById(e.source.guid);
    var controller = activeControllers[index].controller;
    controller.getView().removeEventListener('close', handleClose);
    controller.off();
    controller.destroy();
    activeControllers.splice(index,1);

    removeSubscribersForWindow(e.source.guid);
}

/**
 * remove all subscribers based on the GUID of a window
 */

function removeSubscribersForWindow(guid) {
    var toRemove = _.where(subscribers, {
        'window' : guid
    });
    _.each(toRemove, function(r) {
        var removed = subscribers.splice(subscribers.indexOf(r), 1);
        if (removed && removed[0] && removed[0].valueListener) {
            console.warn('remove value listener', removed[0]);
            removed[0].component.removeEventListener('value', valueChange);
        }
    });
}

/**
 * Set variable in staballoy and trigger update throughout all subscribers
 */

function setVar(key, value) {
    function setVal(path, val) {
        var schema = vars;
        var pList = path.split('_');
        var len = pList.length;
        for (var i = 0; i < len - 1; i++) {
            var elem = pList[i];
            if (!schema[elem])
                schema[elem] = {};
            schema = schema[elem];
        }

        if (_.isEqual(getVar(path), value))
            return false;

        schema[pList[len - 1]] = val;
        return true;
    }

    if (!setVal(key, value)) {
        return false;
    }

    var toUpdate = _.where(subscribers, {
        "var" : key
    });
    _.each(toUpdate, function(sub) {
        trigger(sub);
    });
}

/**
 * Trigger a variable update
 */
function trigger(sub){
    var value = getVar(sub.var);

    if (sub.logicFunction){
        value = sub.logicFunction(value, sub);
    }

    if (sub.attribute.indexOf('set') === 0){
        return sub.component[sub.attribute](value);
    }

    sub.component[sub.attribute] = value;
}

/**
 * Get variable from staballoy
 */

function getVar(key) {

    function getVal(path) {
        var schema = vars;
        var pList = path.split('_');
        var len = pList.length;
        for (var i = 0; i < len - 1; i++) {
            var elem = pList[i];
            if (!schema[elem])
                return false;
            schema = schema[elem];
        }
        return _.clone(schema[pList[len - 1]]);
    }

    return getVal(key);
}

/**
 * Check if, based on ApiName, a subscription is allowed
 */
function isSubscribable(apiName){
    return apiName === 'Ti.UI.Window' || apiName === 'Ti.UI.iOS.NavigationWindow' || apiName === 'Ti.UI.TabGroup';
}

/**
 * Method to get a unique GUID (from Alloy source code)
 */
function guid() {
    function S4() {
        return (65536 * (1 + Math.random()) | 0).toString(16).substring(1);
    }

    return S4() + S4() + "-" + S4() + "-" + S4() + "-" + S4() + "-" + S4() + S4() + S4();
}

module.exports = {
    setVar: setVar,
    getVar: getVar
};
<commit_msg>add double subscribing prevention<commit_after>/**
 * Staballoy is created by Rene Pot (2017)
 * Version 0.2.4 -- 2017-12-05
 * It extends alloy to add reactive components to Titanium.
 * The latest version can be found at Github: https://github.com/topener/staballoy
 */

var requiredControllers = {};
var activeControllers = [];
var subscribers = [];
var vars = {};
var currentlyFocussed = false;

/**
 * Alloy.createController override
 */
Alloy.createController = function(name, args) {
    var args = args || {};

    if (Alloy.CFG.debug) console.log('creating controller in staballoy: ', name, args);

    if (!requiredControllers[name]){
        requiredControllers[name] = require("/alloy/controllers/" + name);
    }
    var controllerGuid = guid();
    args.staballoy = {setVar: setVar, getVar: getVar, guid: controllerGuid};
    args.subscribe = subscribe;
    var controller = new (requiredControllers[name])(args);
    controller.getView().guid = controllerGuid;

    // only parse through all subscribable components
    if (isSubscribable(controller.getView().apiName)){
        if (controller.getView().apiName == 'Ti.UI.iOS.NavigationWindow'){
            parseChildren([controller.getView().window], controller);
        } else {
            parseChildren(controller.getView().children, controller);
        }
        if (controller.getView().staballoy){
            parseSubscriptions(controller.getView(), controller);
        }
        activeControllers.push({controller: controller, guid: controllerGuid});
        controller.getView().addEventListener('focus', handleFocus);
        controller.getView().addEventListener('close', handleClose);

        if (!currentlyFocussed){
            currentlyFocussed = controllerGuid;
        }
    }
    return controller;
};

/**
 * look through all UI elements and find those that need subscribing
 */
function parseChildren(children, controller){
    _.each(children, function(child){
        if (child.children && child.children.length > 0){
            parseChildren(child.children, controller);
            if (child.staballoy){
                parseSubscriptions(child, controller);
            }
        } else if (child.sections && child.sections.length > 0){
            parseChildren(child.sections, controller);
        }

        if (child.staballoy){
            parseSubscriptions(child, controller);
        }
    });
}

/**
 * parse through all subscriptions of the component
 */
function parseSubscriptions(elem, controller){
    if (!elem.staballoy.subscriptions || elem.staballoy.subscriptions.length == 0) return;

    // subscriptions have already been created. Don't do it again
    if (elem.staballoy.guid) return;

    _.each(elem.staballoy.subscriptions, function(attribute, variable){
        var subscriberId = elem.staballoy.guid || guid();
        // create a subscription model
        var data = {"var": variable,  "component": elem, "attribute": attribute, "window": controller.args.staballoy.guid, guid: subscriberId};
        elem.staballoy.guid = subscriberId;

        if (elem.staballoy.logicFunction){
            if (typeof elem.staballoy.logicFunction == 'string'){

                if (controller[elem.staballoy.logicFunction] && typeof controller[elem.staballoy.logicFunction] == 'function'){
                    data.logicFunction = controller[elem.staballoy.logicFunction];
                }
            } else {
                data.logicFunction = elem.staballoy.logicFunction;
            }
        }

        if (attribute === 'value'){
          elem.addEventListener('change', valueChange);
          data.valueListener = true;
        }

        trigger(data);
        subscribers.push(data);
    });
}

function valueChange(e) {
    if (e.source && e.source.staballoy) {
        _.each(e.source.staballoy.subscriptions, function(attribute, variable) {
            if (attribute === 'value') {
                setVar(variable, e.source.value, e.source.staballoy.guid);
            }
        });
    }
}

/**
 * The in-controller exposed subscribe method
 */
function subscribe(args){

    if (typeof args.window == 'string' && getWindowIndexById(args.window) > -1){
        args.window = activeControllers[getWindowIndexById(args.window)].controller;
    }

    if (!isSubscribable(args.window.getView().apiName)){
        return console.error('subscription not possible without context window');
    }

    if (!args.subscriptions || args.subscriptions.length == 0) return;

    args.component.staballoy = {subscriptions: args.subscriptions, logicFunction: args.logicFunction};
    parseSubscriptions(args.component, args.window);

}

/**
 * handle focus and store which is focussed last
 */
function handleFocus(e){
    currentlyFocussed = e.source.guid;
}

function getWindowIndexById(guid){
    return _.findIndex(activeControllers, function(c){
        return c.guid == guid;
    });
}

/**
 * Callback method on the close event listener
 */
function handleClose(e){
    var index = getWindowIndexById(e.source.guid);
    var controller = activeControllers[index].controller;
    controller.getView().removeEventListener('close', handleClose);
    controller.off();
    controller.destroy();
    activeControllers.splice(index,1);

    removeSubscribersForWindow(e.source.guid);
}

/**
 * remove all subscribers based on the GUID of a window
 */

function removeSubscribersForWindow(guid) {
    var toRemove = _.where(subscribers, {
        'window' : guid
    });
    _.each(toRemove, function(r) {
        var removed = subscribers.splice(subscribers.indexOf(r), 1);
        if (removed && removed[0] && removed[0].valueListener) {
            console.warn('remove value listener', removed[0]);
            removed[0].component.removeEventListener('value', valueChange);
        }
    });
}

/**
 * Set variable in staballoy and trigger update throughout all subscribers
 */

function setVar(key, value, sourceguid) {
    function setVal(path, val) {
        var schema = vars;
        var pList = path.split('_');
        var len = pList.length;
        for (var i = 0; i < len - 1; i++) {
            var elem = pList[i];
            if (!schema[elem])
                schema[elem] = {};
            schema = schema[elem];
        }

        if (_.isEqual(getVar(path), value))
            return false;

        schema[pList[len - 1]] = val;
        return true;
    }

    if (!setVal(key, value)) {
        return false;
    }

    var toUpdate = _.where(subscribers, {
        "var" : key
    });
    _.each(toUpdate, function(sub) {
        // only update if the origin of the change isn't itself
        if (!sourceguid || sourceguid !== sub.guid)
            trigger(sub);
    });
}

/**
 * Trigger a variable update
 */
function trigger(sub){
    var value = getVar(sub.var);

    if (sub.logicFunction){
        value = sub.logicFunction(value, sub);
    }

    if (sub.attribute.indexOf('set') === 0){
        return sub.component[sub.attribute](value);
    }

    sub.component[sub.attribute] = value;
}

/**
 * Get variable from staballoy
 */

function getVar(key) {

    function getVal(path) {
        var schema = vars;
        var pList = path.split('_');
        var len = pList.length;
        for (var i = 0; i < len - 1; i++) {
            var elem = pList[i];
            if (!schema[elem])
                return false;
            schema = schema[elem];
        }
        return _.clone(schema[pList[len - 1]]);
    }

    return getVal(key);
}

/**
 * Check if, based on ApiName, a subscription is allowed
 */
function isSubscribable(apiName){
    return apiName === 'Ti.UI.Window' || apiName === 'Ti.UI.iOS.NavigationWindow' || apiName === 'Ti.UI.TabGroup';
}

/**
 * Method to get a unique GUID (from Alloy source code)
 */
function guid() {
    function S4() {
        return (65536 * (1 + Math.random()) | 0).toString(16).substring(1);
    }

    return S4() + S4() + "-" + S4() + "-" + S4() + "-" + S4() + "-" + S4() + S4() + S4();
}

module.exports = {
    setVar: setVar,
    getVar: getVar
};
<|endoftext|>


<commit_before>var assert = require('assert'),
    jsonip = require('../app');

module.exports = {
  'test GET /': function() {
    assert.response(jsonip, {
      url: '/'
    }, {
      body: '{"ip":"127.0.0.1"}'
    });
  },
  'test jsonp callback': function() {
    assert.response(jsonip, {
      url: '/?callback=test'
    }, {
      body: 'test({"ip":"127.0.0.1"});'
    });
  },
  'test optional domain support': function() {
    assert.response(jsonip, {
      url: '/?domains=1'
    }, {
      body: '{"ip":"127.0.0.1","domains":["localhost"]}'
    });
  }
}
<commit_msg>Test for using callback and domains<commit_after>var assert = require('assert'),
    jsonip = require('../app');

module.exports = {
  'test GET /': function() {
    assert.response(jsonip, {
      url: '/'
    }, {
      body: '{"ip":"127.0.0.1"}'
    });
  },
  'test jsonp callback': function() {
    assert.response(jsonip, {
      url: '/?callback=test'
    }, {
      body: 'test({"ip":"127.0.0.1"});'
    });
  },
  'test optional domain support': function() {
    assert.response(jsonip, {
      url: '/?domains=1'
    }, {
      body: '{"ip":"127.0.0.1","domains":["localhost"]}'
    });
  },
  'test jsonp with domains': function() {
    assert.response(jsonip, {
      url: '/?callback=domaintest&domains=1'
    }, {
      body: 'domaintest({"ip":"127.0.0.1","domains":["localhost"]});'
    });
  }
}
<|endoftext|>


<commit_before>const async = require('async');
const diffPatcher = require('jsondiffpatch').create();

const History = require('./diffHistoryModel');

const saveHistoryObject = function(history, callback) {
  history.save(function(err) {
    if (err) {
      err.message = 'Mongo Error :' + err.message;
    }
    callback();
  });
};

const saveDiffObject = function(currentObject, original, updated, user, reason, callback) {
  const diff = diffPatcher.diff(
    JSON.parse(JSON.stringify(original)),
    JSON.parse(JSON.stringify(updated))
  );
  if (diff) {
    History.findOne({
      collectionName: currentObject.constructor.modelName,
      collectionId: currentObject._id
    })
      .sort('-version')
      .exec(function(err, lastHistory) {
        if (err) {
          err.message = 'Mongo Error :' + err.message;
          return callback();
        }
        const history = new History({
          collectionName: currentObject.constructor.modelName,
          collectionId: currentObject._id,
          diff: diff,
          user: user,
          reason: reason,
          version: lastHistory ? lastHistory.version + 1 : 0
        });
        saveHistoryObject(history, callback);
      });
  } else {
    callback();
  }
};

const saveDiffHistory = function(queryObject, currentObject, callback) {
  currentObject.constructor.findOne({ _id: currentObject._id }, function(err, selfObject) {
    if (selfObject) {
      const dbObject = {};
      const updateParams = queryObject._update['$set']
        ? queryObject._update['$set']
        : queryObject._update;
      Object.keys(updateParams).forEach(function(key) {
        dbObject[key] = selfObject[key];
      });
      saveDiffObject(
        currentObject,
        dbObject,
        updateParams,
        queryObject.options.__user,
        queryObject.options.__reason,
        function() {
          callback();
        }
      );
    }
  });
};

const saveDiffs = function(self, next) {
  const queryObject = self;
  queryObject.find(queryObject._conditions, function(err, results) {
    if (err) {
      err.message = 'Mongo Error :' + err.message;
      return next();
    }
    async.eachSeries(
      results,
      function(result, callback) {
        if (err) {
          err.message = 'Mongo Error :' + err.message;
          return next();
        }
        saveDiffHistory(queryObject, result, callback);
      },
      function done() {
        return next();
      }
    );
  });
};

const getVersion = function(model, id, version, callback) {
  model.findOne({ _id: id }, function(err, latest) {
    if (err) {
      console.error(err);
      return callback(err, null);
    }
    History.find(
      {
        collectionName: model.modelName,
        collectionId: id,
        version: { $gte: parseInt(version, 10) }
      },
      { diff: 1, version: 1 },
      { sort: '-version' },
      function(err, histories) {
        if (err) {
          console.error(err);
          return callback(err, null);
        }
        const object = latest ? latest : {};
        async.each(
          histories,
          function(history, eachCallback) {
            diffPatcher.unpatch(object, history.diff);
            eachCallback();
          },
          function(err) {
            if (err) {
              console.error(err);
              return callback(err, null);
            }
            callback(null, object);
          }
        );
      }
    );
  });
};

const getHistories = function(modelName, id, expandableFields, callback) {
  History.find({ collectionName: modelName, collectionId: id }, function(err, histories) {
    if (err) {
      console.error(err);
      return callback(err, null);
    }
    async.map(
      histories,
      function(history, mapCallback) {
        const changedValues = [];
        const changedFields = [];
        for (const key in history.diff) {
          if (history.diff.hasOwnProperty(key)) {
            if (expandableFields.indexOf(key) > -1) {
              //var oldDate = new Date(history.diff[key][0]);
              //var newDate = new Date(history.diff[key][1]);
              //if (oldDate != "Invalid Date" && newDate != "Invalid Date") {
              //    oldValue = oldDate.getFullYear() + "-" + (oldDate.getMonth() + 1) + "-" + oldDate.getDate();
              //    newValue = newDate.getFullYear() + "-" + (newDate.getMonth() + 1) + "-" + newDate.getDate();
              //}
              //else {
              const oldValue = history.diff[key][0];
              const newValue = history.diff[key][1];
              //}
              changedValues.push(key + ' from ' + oldValue + ' to ' + newValue);
            } else {
              changedFields.push(key);
            }
          }
        }
        const comment = 'modified ' + changedFields.concat(changedValues).join(', ');
        return mapCallback(null, {
          changedBy: history.user,
          changedAt: history.createdAt,
          updatedAt: history.updatedAt,
          reason: history.reason,
          comment: comment
        });
      },
      function(err, output) {
        if (err) {
          console.error(err);
          return callback(err, null);
        }
        return callback(null, output);
      }
    );
  });
};

const plugin = function lastModifiedPlugin(schema) {
  schema.pre('save', function(next) {
    const self = this;
    if (self.isNew) {
      next();
    } else {
      self.constructor.findOne({ _id: self._id }, function(err, original) {
        saveDiffObject(self, original, self, self.__user, self.__reason, function() {
          next();
        });
      });
    }
  });

  schema.pre('findOneAndUpdate', function(next) {
    saveDiffs(this, function() {
      next();
    });
  });

  schema.pre('update', function(next) {
    saveDiffs(this, function() {
      next();
    });
  });

  schema.pre('remove', function(next) {
    saveDiffObject(this, this, {}, this.__user, this.__reason, function() {
      next();
    });
  });
};

module.exports.plugin = plugin;
module.exports.getHistories = getHistories;
module.exports.getVersion = getVersion;
<commit_msg>Remove commented out code.<commit_after>const async = require('async');
const diffPatcher = require('jsondiffpatch').create();

const History = require('./diffHistoryModel');

const saveHistoryObject = function(history, callback) {
  history.save(function(err) {
    if (err) {
      err.message = 'Mongo Error :' + err.message;
    }
    callback();
  });
};

const saveDiffObject = function(currentObject, original, updated, user, reason, callback) {
  const diff = diffPatcher.diff(
    JSON.parse(JSON.stringify(original)),
    JSON.parse(JSON.stringify(updated))
  );
  if (diff) {
    History.findOne({
      collectionName: currentObject.constructor.modelName,
      collectionId: currentObject._id
    })
      .sort('-version')
      .exec(function(err, lastHistory) {
        if (err) {
          err.message = 'Mongo Error :' + err.message;
          return callback();
        }
        const history = new History({
          collectionName: currentObject.constructor.modelName,
          collectionId: currentObject._id,
          diff: diff,
          user: user,
          reason: reason,
          version: lastHistory ? lastHistory.version + 1 : 0
        });
        saveHistoryObject(history, callback);
      });
  } else {
    callback();
  }
};

const saveDiffHistory = function(queryObject, currentObject, callback) {
  currentObject.constructor.findOne({ _id: currentObject._id }, function(err, selfObject) {
    if (selfObject) {
      const dbObject = {};
      const updateParams = queryObject._update['$set']
        ? queryObject._update['$set']
        : queryObject._update;
      Object.keys(updateParams).forEach(function(key) {
        dbObject[key] = selfObject[key];
      });
      saveDiffObject(
        currentObject,
        dbObject,
        updateParams,
        queryObject.options.__user,
        queryObject.options.__reason,
        function() {
          callback();
        }
      );
    }
  });
};

const saveDiffs = function(self, next) {
  const queryObject = self;
  queryObject.find(queryObject._conditions, function(err, results) {
    if (err) {
      err.message = 'Mongo Error :' + err.message;
      return next();
    }
    async.eachSeries(
      results,
      function(result, callback) {
        if (err) {
          err.message = 'Mongo Error :' + err.message;
          return next();
        }
        saveDiffHistory(queryObject, result, callback);
      },
      function done() {
        return next();
      }
    );
  });
};

const getVersion = function(model, id, version, callback) {
  model.findOne({ _id: id }, function(err, latest) {
    if (err) {
      console.error(err);
      return callback(err, null);
    }
    History.find(
      {
        collectionName: model.modelName,
        collectionId: id,
        version: { $gte: parseInt(version, 10) }
      },
      { diff: 1, version: 1 },
      { sort: '-version' },
      function(err, histories) {
        if (err) {
          console.error(err);
          return callback(err, null);
        }
        const object = latest ? latest : {};
        async.each(
          histories,
          function(history, eachCallback) {
            diffPatcher.unpatch(object, history.diff);
            eachCallback();
          },
          function(err) {
            if (err) {
              console.error(err);
              return callback(err, null);
            }
            callback(null, object);
          }
        );
      }
    );
  });
};

const getHistories = function(modelName, id, expandableFields, callback) {
  History.find({ collectionName: modelName, collectionId: id }, function(err, histories) {
    if (err) {
      console.error(err);
      return callback(err, null);
    }
    async.map(
      histories,
      function(history, mapCallback) {
        const changedValues = [];
        const changedFields = [];
        for (const key in history.diff) {
          if (history.diff.hasOwnProperty(key)) {
            if (expandableFields.indexOf(key) > -1) {
              const oldValue = history.diff[key][0];
              const newValue = history.diff[key][1];
              changedValues.push(key + ' from ' + oldValue + ' to ' + newValue);
            } else {
              changedFields.push(key);
            }
          }
        }
        const comment = 'modified ' + changedFields.concat(changedValues).join(', ');
        return mapCallback(null, {
          changedBy: history.user,
          changedAt: history.createdAt,
          updatedAt: history.updatedAt,
          reason: history.reason,
          comment: comment
        });
      },
      function(err, output) {
        if (err) {
          console.error(err);
          return callback(err, null);
        }
        return callback(null, output);
      }
    );
  });
};

const plugin = function lastModifiedPlugin(schema) {
  schema.pre('save', function(next) {
    const self = this;
    if (self.isNew) {
      next();
    } else {
      self.constructor.findOne({ _id: self._id }, function(err, original) {
        saveDiffObject(self, original, self, self.__user, self.__reason, function() {
          next();
        });
      });
    }
  });

  schema.pre('findOneAndUpdate', function(next) {
    saveDiffs(this, function() {
      next();
    });
  });

  schema.pre('update', function(next) {
    saveDiffs(this, function() {
      next();
    });
  });

  schema.pre('remove', function(next) {
    saveDiffObject(this, this, {}, this.__user, this.__reason, function() {
      next();
    });
  });
};

module.exports.plugin = plugin;
module.exports.getHistories = getHistories;
module.exports.getVersion = getVersion;
<|endoftext|>