com.qmetry.qaf.automation.step.client.AbstractScenarioFileParser.java Source code

Java tutorial

Introduction

Here is the source code for com.qmetry.qaf.automation.step.client.AbstractScenarioFileParser.java

Source

/*******************************************************************************
 * QMetry Automation Framework provides a powerful and versatile platform to author 
 * Automated Test Cases in Behavior Driven, Keyword Driven or Code Driven approach
 *                
 * Copyright 2016 Infostretch Corporation
 *
 * This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or any later version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
 *
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT
 * OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE
 *
 * You should have received a copy of the GNU General Public License along with this program in the name of LICENSE.txt in the root folder of the distribution. If not, see https://opensource.org/licenses/gpl-3.0.html
 *
 * See the NOTICE.TXT file in root folder of this source files distribution 
 * for additional information regarding copyright ownership and licenses
 * of other open source software / files used by QMetry Automation Framework.
 *
 * For any inquiry or need additional information, please contact support-qaf@infostretch.com
 *******************************************************************************/

package com.qmetry.qaf.automation.step.client;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.impl.LogFactoryImpl;
import org.json.JSONException;

import com.google.gson.Gson;
import com.google.gson.JsonSyntaxException;
import com.qmetry.qaf.automation.step.StringTestStep;
import com.qmetry.qaf.automation.step.TestStep;
import com.qmetry.qaf.automation.testng.dataprovider.QAFDataProvider.params;
import com.qmetry.qaf.automation.util.FileUtil;
import com.qmetry.qaf.automation.util.JSONUtil;
import com.qmetry.qaf.automation.util.StringUtil;

/**
 * @author chirag.jayswal
 */
public abstract class AbstractScenarioFileParser implements ScenarioFileParser {

    public static final String STEP_DEF = "STEP-DEF";
    public static final String END = "END";
    public static final String TEST_DATA = "TEST-DATA";
    public static final String SCENARIO = "SCENARIO";
    public static final String DESCRIPTION = "desc";

    protected final Log logger;

    private Gson gson;
    private List<String> includeGroups;
    private List<String> excludeGroups;

    public AbstractScenarioFileParser() {
        logger = LogFactoryImpl.getLog(getClass());
        gson = new Gson();
        this.includeGroups = new ArrayList<String>();
        this.excludeGroups = new ArrayList<String>();
    }

    @Override
    public void parse(String scenarioFile, List<Scenario> scenarios) {
        Collection<Object[]> statements = parseFile(scenarioFile);
        String reference = FileUtil.getRelativePath(scenarioFile, "./");
        processStatements(statements.toArray(new Object[0][0]), reference, scenarios);
    }

    @Override
    public void setExcludeGroups(List<String> excludeGroups) {
        this.excludeGroups = excludeGroups;
    }

    @Override
    public void setIncludeGroups(List<String> includeGroups) {
        this.includeGroups = includeGroups;
    }

    /**
     * This method expects file parser to parse file and return collection of
     * Object array of size 4. Elements of array should be as follow:
     * <DL>
     * <DT>Step call should be array containing:
     * <DD>
     * <code>["step-name-or-description-to-call", "inParams", "outParam", lineNo(optional)]</code>
     * </DD></DT>
     * <DT>Scenario Definition should be array containing:
     * <DD>
     * <code>["SCENARIO", "SCENARIO-name", "meta-data", lineNo(optional)]</code>
     * </DD></DT>
     * </DL>
     * <DT>Step Definition should be array containing:
     * <DD>
     * <code>["STEP-DEF", "step-name-or-description", "meta-data", lineNo(optional)]</code>
     * </DD></DT>
     * </DL>
     * </p>
     * Step-Def
     * 
     * @param scenarioFile
     * @return
     */
    protected abstract Collection<Object[]> parseFile(String scenarioFile);

    protected void processStatements(Object[][] statements, String referece, List<Scenario> scenarios) {

        for (int statementIndex = 0; statementIndex < statements.length; statementIndex++) {

            String type = ((String) statements[statementIndex][0]).trim();

            // ignore blanks and statements outside scenario or step-def
            if (StringUtil.isBlank(type) || type.equalsIgnoreCase(TEST_DATA) || !(type.equalsIgnoreCase(STEP_DEF)
                    || type.equalsIgnoreCase(SCENARIO) || type.equalsIgnoreCase(END))) {
                String nextSteptype = "";
                do {
                    statementIndex++;
                    if (statements.length > (statementIndex + 2)) {
                        nextSteptype = ((String) statements[statementIndex + 1][0]).trim();
                    } else {
                        nextSteptype = END; //
                    }
                } while (!(nextSteptype.equalsIgnoreCase(STEP_DEF) || nextSteptype.equalsIgnoreCase(SCENARIO)
                        || nextSteptype.equalsIgnoreCase(END)));
            }

            // Custom step definition
            if (type.equalsIgnoreCase(STEP_DEF)) {
                statementIndex = parseStepDef(statements, statementIndex, referece);
            } else if (type.equalsIgnoreCase(SCENARIO)) {
                statementIndex = parseScenario(statements, statementIndex, referece, scenarios);
            }
        }

    }

    protected int parseStepDef(Object[][] statements, int statementIndex, String referece) {

        Object[] stepDef = statements[statementIndex];

        String stepName = stepDef.length > 1 ? ((String) stepDef[1]).trim() : "";
        String description = stepName;

        int lineNo = getLineNum(statements, statementIndex);
        ArrayList<TestStep> steps = new ArrayList<TestStep>();

        CustomStep customStep = new CustomStep(stepName, StringUtil.isBlank(description) ? stepName : description,
                steps);
        customStep.setFileName(referece);
        customStep.setLineNumber(lineNo);

        String nextSteptype = "";
        do {
            statementIndex++;
            lineNo = getLineNum(statements, statementIndex);

            String currStepName = (String) statements[statementIndex][0];

            if (!currStepName.equalsIgnoreCase(END)) {
                StringTestStep step = new StringTestStep((String) statements[statementIndex][0],
                        gson.fromJson((String) statements[statementIndex][1], Object[].class));
                step.setResultParamName((String) statements[statementIndex][2]);
                step.setFileName(referece);
                step.setLineNumber(lineNo);
                steps.add(step);
            }
            if (statements.length > (statementIndex + 2)) {
                nextSteptype = ((String) statements[statementIndex + 1][0]).trim();
            } else {
                nextSteptype = END; //
            }
        } while (!(nextSteptype.equalsIgnoreCase(STEP_DEF) || nextSteptype.equalsIgnoreCase(SCENARIO)
                || nextSteptype.equalsIgnoreCase(END) || nextSteptype.equalsIgnoreCase(TEST_DATA)));

        if (stepDef.length > 2 && null != stepDef[2]) {
            try {
                String metadatastr = (String) stepDef[2];

                Map<String, Object> metadata = StringUtil.isBlank(metadatastr) ? new HashMap<String, Object>()
                        : JSONUtil.toMap(metadatastr);
                customStep.setMetaData(metadata);

                if (metadata.containsKey("name")) {
                    stepName = (String) metadata.get("name");
                    customStep.setName(stepName);

                }
                if (metadata.containsKey("description")) {
                    description = (String) metadata.get("description");
                    customStep.setDescription(description);
                }
                if (metadata.containsKey("threshold")) {
                    int threshold = ((Number) metadata.get("threshold")).intValue();
                    customStep.setThreshold(threshold);
                }

            } catch (JSONException e) {

            }
        }
        StringTestStep.addStep(stepName, customStep);

        return statementIndex;
    }

    @SuppressWarnings("unchecked")
    protected int parseScenario(Object[][] statements, int statementIndex, String referece,
            List<Scenario> scenarios) {

        String description = statements[statementIndex].length > 2 ? (String) statements[statementIndex][2] : "";
        String stepName = statements[statementIndex].length > 1 ? ((String) statements[statementIndex][1]).trim()
                : "";

        int lineNo = getLineNum(statements, statementIndex);

        // collect all steps of scenario
        Collection<TestStep> steps = new ArrayList<TestStep>();

        Map<String, Object> metadata = new TreeMap<String, Object>(String.CASE_INSENSITIVE_ORDER);
        if (StringUtil.isNotBlank(description)) {
            metadata.putAll(gson.fromJson(description, Map.class));
        }
        metadata.put("referece", referece);
        metadata.put("lineNo", lineNo);

        /**
         * check enabled flag in meta-data and apply groups filter if configured
         * in xml configuration file. the custom meta-data filter will covered
         * in method filter where it will not include groups from xml
         * configuration file.
         */
        if (include(includeGroups, excludeGroups, metadata)) {
            String dataProvider = getDP(metadata);
            Scenario scenario = StringUtil.isBlank(dataProvider) ? new Scenario(stepName, steps, metadata)
                    : new DataDrivenScenario(stepName, steps, dataProvider, metadata);

            scenarios.add(scenario);
        } else {
            logger.debug("Excluded SCENARIO - " + stepName + ":" + metadata.get(DESCRIPTION));
        }
        String nextSteptype = "";
        do {
            statementIndex++;
            lineNo = getLineNum(statements, statementIndex);

            String currStepName = (String) statements[statementIndex][0];
            if (!currStepName.equalsIgnoreCase(END)) {
                TestStep step = parseStepCall(statements[statementIndex], referece, lineNo);
                steps.add(step);
            }

            if (statements.length > (statementIndex + 2)) {
                nextSteptype = ((String) statements[statementIndex + 1][0]).trim();
            } else {
                nextSteptype = END; // EOF
            }
        } while (!(nextSteptype.equalsIgnoreCase(STEP_DEF) || nextSteptype.equalsIgnoreCase(SCENARIO)
                || nextSteptype.equalsIgnoreCase(END) || nextSteptype.equalsIgnoreCase(TEST_DATA)));

        return statementIndex;

    }

    protected TestStep parseStepCall(Object[] statement, String referece, int lineNo) {

        String currStepName = (String) statement[0];
        Object[] currStepArgs = null;
        try {
            currStepArgs = (StringUtil.isNotBlank((String) statement[1]))
                    ? gson.fromJson((String) statement[1], Object[].class)
                    : null;
        } catch (JsonSyntaxException jse) {
            logger.error(jse.getMessage() + statement[1], jse);
        }
        String currStepRes = statement.length > 2 ? (String) statement[2] : "";

        StringTestStep step = new StringTestStep(currStepName, currStepArgs);
        step.setResultParamName(currStepRes);
        step.setFileName(referece);
        step.setLineNumber(lineNo);

        return step;

    }

    private int getLineNum(Object[][] statements, int statementIndex) {
        try {
            return (statements[statementIndex].length > 3 && null != statements[statementIndex][3]
                    ? (Integer) statements[statementIndex][3]
                    : statementIndex);
        } catch (Exception e) {// not a number???...
            return statementIndex;
        }
    }

    protected String getDP(Map<String, Object> metadata) {
        String dataProvider = "";
        for (params key : params.values()) {
            if (metadata.containsKey(key.name())) {
                dataProvider = String.format("%s%s%s=%s", dataProvider,
                        StringUtil.isNotBlank(dataProvider) ? ";" : "", key, metadata.get(key.name()));
            }
        }
        return dataProvider;
    }

    /**
     * To apply groups and enabled filter
     * 
     * @param includeGroups
     * @param excludeGroups
     * @param metadata
     * @return
     */
    @SuppressWarnings("unchecked")
    protected boolean include(List<String> includeGroups, List<String> excludeGroups,
            Map<String, Object> metadata) {
        // check for enabled
        if (metadata.containsKey("enabled") && !((Boolean) metadata.get("enabled")))
            return false;

        Set<Object> groups = new HashSet<Object>(
                metadata.containsKey(ScenarioFactory.GROUPS) ? (List<String>) metadata.get(ScenarioFactory.GROUPS)
                        : new ArrayList<String>());
        if (!includeGroups.isEmpty()) {
            groups.retainAll(includeGroups);
        }
        groups.removeAll(excludeGroups);
        return (!groups.isEmpty() || (includeGroups.isEmpty() && excludeGroups.isEmpty()));
    }
}