Source: Test.js

const ParserError = require("./ParserError");
const Util = require("../util/Util");

/**
 * Represent a single test
 */
class Test {
    /**
     *
     * @param {TestSuite} suite - The test suite that contains this test.
     * @param {string | object} metadata - Metadata includes the description as a string or an object including the
     * description property.
     * @param {array} interactions - The interactions that form this test
     */
    constructor(suite, metadata, interactions) {
        this._testSuite = suite;
        this._description = undefined;
        if (metadata) {
            if (Util.isString(metadata)) {
                this._description = metadata;
            } else {
                this._metadata = metadata;
                this._description = metadata.description;
            }
        }
        this._interactions = interactions;
        this._skip = false;
        this._only = false;
        this._index = 0;
        this._tags = [];
    }

    /**
     * Get the Test's description.
     * @return {string} The test description.
     */
    get description() {
        return this._description;
    }

    /**
     * Set the Test's description.
     * @param {string} value - test description
     */
    set description(value) {
        this._description = value;
    }

    /**
     * Get the Test's index.
     * @return {number} The test index.
     */
    get index() {
        return this._index;
    }

    /**
     * Set the Test's index.
     * @param {number} value - test index
     */
    set index(value) {
        this._index = value;
    }

    /**
     * Get the Test's tags.
     * @return {number} The test tags.
     */
    get tags() {
        return this._tags;
    }

    /**
     * Set the Test's tags.
     * @param {Array} value - test tags
     */
    set tags(value) {
        this._tags = value;
    }

    /**
     * Indicates if this test uses goto
     * @return {boolean} true if it includes goto, false if not.
     */
    get hasGoto() {
        return this.interactions.find(interaction => interaction.hasGoto);
    }

    /**
     * Indicates if this test uses exit
     * @return {boolean} true if it includes exit, false if not.
     */
    get hasExit() {
        return this.interactions.find(interaction => interaction.hasExit);
    }

    /**
     * Returns true if at least one of the interactions have operator "==" or "=~"
     * @return {boolean}
     */
    get hasDeprecatedOperators() {
        return this.interactions.some(interaction => interaction.hasDeprecatedOperators);
    }

    /**
     * Returns true if at least one of the interactions have operator ">", ">=", "<" and "<="
     * @return {boolean}
     */
    get hasDeprecatedE2EOperators() {
        return this.interactions.some(interaction => interaction.hasDeprecatedE2EOperators);
    }

    /**
     * Get the Test's interactions.
     * @return {TestInteraction[]} The test's interactions.
     */
    get interactions() {
        return this._interactions;
    }

    /****
     * If true this will be the only test to run.
     * @return {boolean} true if only flag is active, false if not.
     */
    get only() {
        return this._only;
    }

    /**
     * If set to true this will be the only test to run.
     * @param {boolean} only - only flag
     */
    set only(only) {
        this._only = only;
    }

    /****
     * If true this test will be skipped
     * @return {boolean} true if skip flag is active, false if not.
     */
    get skip() {
        return this._skip;
    }

    /**
     * If set to true this test will be skipped
     * @param {boolean} skip - skip flag
     */
    set skip(skip) {
        this._skip = skip;
    }

    /**
     * Returns the complete test suite
     * @return {TestSuite} the test suite
     */
    get testSuite() {
        return this._testSuite;
    }

    /**
     *  Make sure all any goto statements work
     * @return {boolean} Returns true if all goto have a matching utterance
     * @throws {ParserError} Throws a Parser Error if any goto doesn't have a matching utterance
     */
    validate() {
        for (const interaction of this.interactions) {
            for (const assertion of interaction.assertions) {
                if (assertion.goto) {
                    let matched = false;
                    for (const i2 of this.interactions) {
                        if (i2.utterance === assertion.goto || i2.label == assertion.goto) {
                            matched = true;
                            break;
                        }
                    }

                    if (!matched) {
                        throw ParserError.error(this.testSuite.fileName,
                            "No match for goto: " + assertion.goto,
                            assertion.lineNumber);
                    }
                }
            }
        }
        return true;
    }

    /**
     * Returns a non-circular DTO version of this Test
     * @return {object} a DTO including the description and interactions
     */
    toDTO() {
        return {
            description: this.description,
            interactions: this.interactions.map(interaction => interaction.toDTO()),
            only: this.only,
            skip: this.skip,
        };
    }

    /**
     * Returns the test as a yaml object
     * { name: string, interaction:s object[]}
     * @return {object}
    */
    toYamlObject() {
        return {
            interactions: this.interactions.map(interaction => interaction.toYamlObject()),
            name: this.description,
            only: this.only,
            skip: this.skip,
            tags: this.tags,
        };
    }
}

module.exports = Test;