"use strict"; /** * Tests generator. * * @module */ require("colors"); var _ = require("lodash"); var prettyms = require("pretty-ms"); var U = require("glace-utils"); var CONF = require("./config"); var loadSteps = require("./loader").loadSteps; var Test = require("./test"); var train = require("./train"); /** * Generates test cases. * * @function * @arg {object} opts - Options. * @arg {string} [opts.filter] - Chunk of step name to choose tests which * contain this step. * @return {object[]} - List of generated tests and unused steps. */ exports.generate = opts => { opts = U.defVal(opts, {}); var filter = U.defVal(opts.filter, CONF.gen.filter); var startTime = new Date(); console.log("Generating tests from steps...".yellow); if (CONF.gen.pretrain) { Test.pretrain = U.loadJson(CONF.gen.pretrain); } else { if (CONF.gen.trainBefore) { Test.pretrain = train(CONF.gen.trainBefore); }; } var steps = loadSteps(); var tests = generateTests(steps); var unusedSteps = getUnusedSteps(steps, tests); tests = filterTests(tests, filter); if (CONF.gen.testsMax) { tests = tests.slice(0, CONF.gen.testsMax); } if (CONF.gen.testsReverse) { tests.reverse(); } console.log(`${tests.length} tests are generated during ${prettyms(new Date() - startTime)}`.yellow); return [tests, unusedSteps]; }; /** * Generates tests. * * @ignore * @function * @arg {Step[]} steps * @return {Test[]} */ var generateTests = steps => { var tests = [new Test()]; var isStarted = false; while (!isStarted || changes(tests)) { isStarted = true; var tmp = CONF.gen.testsShuffle ? _.shuffle(tests) : tests; tests = []; for (var t of tmp) { var sameTest = true; if (t.steps.length < CONF.gen.stepsLimit) { for (var s of steps) { if (tests.length >= CONF.gen.testsLimit) break; if (!t.mayAdd(s)) continue; var clone = t.clone(); clone.add(s.clone()); tests.push(clone); sameTest = false; }; }; if (tests.length >= CONF.gen.testsLimit) break; if (sameTest) { t.commit(); tests.push(t); }; }; tests.sort((a, b) => b.weight - a.weight); tests = filterByUniqSteps(tests); }; return tests.filter(t => !t.incomplete.length); }; /** * Filters tests by unique steps sequence. * * @ignore * @function * @arg {Test[]} tests * @return {Test[]} */ var filterByUniqSteps = tests => { var stepsUniq = CONF.gen.stepsUniq; if (stepsUniq) { var stepNames = []; var tmp = []; for (var t of tests) { if (t.steps.length <= stepsUniq) { tmp.push(t); continue; }; var isPresent = true; for (var i = 0; i < t.steps.length - stepsUniq + 1; i++) { var sName = ""; for (var j = 0; j < stepsUniq; j++) { sName += " " + t.steps[i+j].name; }; if (!stepNames.includes(sName)) { stepNames.push(sName); isPresent = false; }; }; if (!isPresent) tmp.push(t); }; tests = tmp; }; return tests; }; /** * Gets unused steps * * @ignore * @function * @arg {Step[]} steps * @return {Step[]} */ var getUnusedSteps = (steps, tests) => { var ss = []; var stepNames = []; for (var t of tests) { for (var s of t.steps) { if (!stepNames.includes(s.name)) { stepNames.push(s.name); }; }; }; for (var step of steps) { if (!stepNames.includes(step.name)) { ss.push(step); }; }; return ss; }; /** * Filters tests * * @ignore * @function * @arg {Test[]} tests * @arg {string} filter * @return {Test[]} */ var filterTests = (tests, filter) => { if (!filter) return tests; var filtered = []; for (var t of tests) { var isMatched = false; for (var s of t.steps) { if (s.name.includes(filter)) { isMatched = true; break; }; }; if (isMatched) filtered.push(t); }; return filtered; }; /** * Defines whether there are changes in tests or no. * * @ignore * @function * @arg {Test[]} * @return {boolean} */ var changes = tests => { for (var t of tests) { if (t.isChanged) return true; }; return false; };