All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.liferay.poshi.runner.PoshiRunnerValidation Maven / Gradle / Ivy

There is a newer version: 1.0.496
Show newest version
/**
 * Copyright (c) 2000-present Liferay, Inc. All rights reserved.
 *
 * This library is free software; you can redistribute it and/or modify it under
 * the terms of the GNU Lesser General Public License as published by the Free
 * Software Foundation; either version 2.1 of the License, or (at your option)
 * any later version.
 *
 * This library 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 Lesser General Public License for more
 * details.
 */

package com.liferay.poshi.runner;

import com.liferay.poshi.runner.util.OSDetector;
import com.liferay.poshi.runner.util.PropsUtil;
import com.liferay.poshi.runner.util.PropsValues;
import com.liferay.poshi.runner.util.StringUtil;
import com.liferay.poshi.runner.util.Validator;

import java.lang.reflect.Method;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.dom4j.Attribute;
import org.dom4j.Element;

/**
 * @author Karen Dang
 * @author Michael Hashimoto
 */
public class PoshiRunnerValidation {

	public static void clearExceptions() {
		_exceptions.clear();
	}

	public static Set getExceptions() {
		return _exceptions;
	}

	public static void main(String[] args) throws Exception {
		PoshiRunnerContext.readFiles();

		validate();
	}

	public static void validate() throws Exception {
		List filePaths = PoshiRunnerContext.getFilePathsList();

		for (String filePath : filePaths) {
			if (OSDetector.isWindows()) {
				filePath = filePath.replace("/", "\\");
			}

			String className = PoshiRunnerGetterUtil.getClassNameFromFilePath(
				filePath);
			String classType = PoshiRunnerGetterUtil.getClassTypeFromFilePath(
				filePath);

			if (classType.equals("function")) {
				Element element = PoshiRunnerContext.getFunctionRootElement(
					className);

				validateFunctionFile(element, filePath);
			}
			else if (classType.equals("macro")) {
				Element element = PoshiRunnerContext.getMacroRootElement(
					className);

				validateMacroFile(element, filePath);
			}
			else if (classType.equals("path")) {
				Element element = PoshiRunnerContext.getPathRootElement(
					className);

				validatePathFile(element, filePath);
			}
			else if (classType.equals("test-case")) {
				Element element = PoshiRunnerContext.getTestCaseRootElement(
					className);

				validateTestCaseFile(element, filePath);
			}
		}

		if (!_exceptions.isEmpty()) {
			_throwExceptions();
		}
	}

	public static void validate(String testName) throws Exception {
		validateTestName(testName);

		validate();
	}

	protected static String getPrimaryAttributeName(
		Element element, List multiplePrimaryAttributeNames,
		List primaryAttributeNames, String filePath) {

		validateHasPrimaryAttributeName(
			element, multiplePrimaryAttributeNames, primaryAttributeNames,
			filePath);

		for (String primaryAttributeName : primaryAttributeNames) {
			if (Validator.isNotNull(
					element.attributeValue(primaryAttributeName))) {

				return primaryAttributeName;
			}
		}

		return null;
	}

	protected static String getPrimaryAttributeName(
		Element element, List primaryAttributeNames, String filePath) {

		return getPrimaryAttributeName(
			element, null, primaryAttributeNames, filePath);
	}

	protected static void parseElements(Element element, String filePath) {
		List childElements = element.elements();

		List possibleElementNames = Arrays.asList(
			"description", "echo", "execute", "fail", "for", "if", "property",
			"return", "take-screenshot", "task", "var", "while");

		if (Validator.isNotNull(filePath) && filePath.endsWith(".function")) {
			possibleElementNames = Arrays.asList("execute", "if");
		}

		for (Element childElement : childElements) {
			String elementName = childElement.getName();

			if (!possibleElementNames.contains(elementName)) {
				_exceptions.add(
					new Exception(
						"Invalid " + elementName + " element\n" + filePath +
							":" + childElement.attributeValue("line-number")));
			}

			if (elementName.equals("description") ||
				elementName.equals("echo") || elementName.equals("fail")) {

				validateMessageElement(childElement, filePath);
			}
			else if (elementName.equals("execute")) {
				validateExecuteElement(childElement, filePath);
			}
			else if (elementName.equals("for")) {
				validateForElement(childElement, filePath);
			}
			else if (elementName.equals("if")) {
				validateIfElement(childElement, filePath);
			}
			else if (elementName.equals("property")) {
				validatePropertyElement(childElement, filePath);
			}
			else if (elementName.equals("return")) {
				validateCommandReturnElement(childElement, filePath);
			}
			else if (elementName.equals("take-screenshot")) {
				validateTakeScreenshotElement(childElement, filePath);
			}
			else if (elementName.equals("task")) {
				validateTaskElement(childElement, filePath);
			}
			else if (elementName.equals("var")) {
				validateVarElement(childElement, filePath);
			}
			else if (elementName.equals("while")) {
				validateWhileElement(childElement, filePath);
			}
		}
	}

	protected static void validateArgElement(Element element, String filePath) {
		List attributes = Arrays.asList("line-number", "value");

		validatePossibleAttributeNames(element, attributes, filePath);
		validateRequiredAttributeNames(element, attributes, filePath);
	}

	protected static void validateClassCommandName(
		Element element, String classCommandName, String classType,
		String filePath) {

		String className =
			PoshiRunnerGetterUtil.getClassNameFromClassCommandName(
				classCommandName);

		if (!PoshiRunnerContext.isRootElement(classType + "#" + className)) {
			_exceptions.add(
				new Exception(
					"Invalid " + classType + " class " + className + "\n" +
						filePath + ":" +
							element.attributeValue("line-number")));
		}

		String commandElementKey = classType + "#" + classCommandName;

		if (!PoshiRunnerContext.isCommandElement(commandElementKey)) {
			_exceptions.add(
				new Exception(
					"Invalid " + classType + " command " + classCommandName +
						"\n" + filePath + ":" +
							element.attributeValue("line-number")));
		}
	}

	protected static void validateCommandElement(
		Element element, String filePath) {

		List possibleAttributeNames = Arrays.asList(
			"line-number", "name", "returns", "summary", "summary-ignore");

		validatePossibleAttributeNames(
			element, possibleAttributeNames, filePath);
		validateRequiredAttributeNames(
			element, Arrays.asList("name"), filePath);

		String returns = element.attributeValue("returns");

		List returnElements =
			PoshiRunnerGetterUtil.getAllChildElements(element, "return");

		if (returns == null) {
			List validReturnElements = new ArrayList<>();

			for (Element returnElement : returnElements) {
				Element parentElement = returnElement.getParent();

				if (!Objects.equals(parentElement.getName(), "execute")) {
					validReturnElements.add(returnElement);
				}
			}

			if (!validReturnElements.isEmpty()) {
				_exceptions.add(
					new Exception(
						element.attributeValue("name") +
							" does not return values\n" + filePath + ":" +
								element.attributeValue("line-number")));
			}
		}
		else {
			List returnsList = Arrays.asList(StringUtil.split(returns));

			for (Element returnElement : returnElements) {
				String returnVariable = returnElement.attributeValue("name");

				if (returnsList.contains(returnVariable)) {
					continue;
				}

				Element parentElement = returnElement.getParent();

				if (Objects.equals(parentElement.getName(), "execute")) {
					continue;
				}

				_exceptions.add(
					new Exception(
						returnVariable + " not listed as a return variable\n" +
							filePath + ":" +
								element.attributeValue("line-number")));
			}
		}
	}

	protected static void validateCommandReturnElement(
		Element element, String filePath) {

		List attributeNames = Arrays.asList(
			"line-number", "name", "value");

		validateHasNoChildElements(element, filePath);
		validatePossibleAttributeNames(element, attributeNames, filePath);
		validateRequiredAttributeNames(element, attributeNames, filePath);
	}

	protected static void validateConditionElement(
		Element element, String filePath) {

		String elementName = element.getName();

		if (elementName.equals("and") || elementName.equals("or")) {
			validateHasChildElements(element, filePath);
			validateHasNoAttributes(element, filePath);

			List childElements = element.elements();

			if (childElements.size() < 2) {
				_exceptions.add(
					new Exception(
						"Too few child elements\n" + filePath + ":" +
							element.attributeValue("line-number")));
			}

			for (Element childElement : childElements) {
				validateConditionElement(childElement, filePath);
			}
		}
		else if (elementName.equals("condition")) {
			List primaryAttributeNames = Arrays.asList(
				"function", "selenium");

			String primaryAttributeName = getPrimaryAttributeName(
				element, primaryAttributeNames, filePath);

			if (Validator.isNull(primaryAttributeName)) {
				return;
			}

			if (primaryAttributeName.equals("function")) {
				validateRequiredAttributeNames(
					element, Arrays.asList("locator1"), filePath);

				List possibleAttributeNames = Arrays.asList(
					"function", "line-number", "locator1", "value1");

				validatePossibleAttributeNames(
					element, possibleAttributeNames, filePath);
			}
			else if (primaryAttributeName.equals("selenium")) {
				List possibleAttributeNames = Arrays.asList(
					"argument1", "argument2", "line-number", "selenium");

				validatePossibleAttributeNames(
					element, possibleAttributeNames, filePath);
			}

			validateHasNoChildElements(element, filePath);
		}
		else if (elementName.equals("contains")) {
			List attributeNames = Arrays.asList(
				"line-number", "string", "substring");

			validateHasNoChildElements(element, filePath);
			validatePossibleAttributeNames(element, attributeNames, filePath);
			validateRequiredAttributeNames(element, attributeNames, filePath);
		}
		else if (elementName.equals("equals")) {
			List attributeNames = Arrays.asList(
				"arg1", "arg2", "line-number");

			validateHasNoChildElements(element, filePath);
			validatePossibleAttributeNames(element, attributeNames, filePath);
			validateRequiredAttributeNames(element, attributeNames, filePath);
		}
		else if (elementName.equals("isset")) {
			List attributeNames = Arrays.asList("line-number", "var");

			validateHasNoChildElements(element, filePath);
			validatePossibleAttributeNames(element, attributeNames, filePath);
			validateRequiredAttributeNames(element, attributeNames, filePath);
		}
		else if (elementName.equals("not")) {
			validateHasChildElements(element, filePath);
			validateHasNoAttributes(element, filePath);
			validateNumberOfChildElements(element, 1, filePath);

			List childElements = element.elements();

			validateConditionElement(childElements.get(0), filePath);
		}
	}

	protected static void validateDefinitionElement(
		Element element, String filePath) {

		String elementName = element.getName();

		if (!Objects.equals(elementName, "definition")) {
			_exceptions.add(
				new Exception(
					"Root element name must be definition\n" + filePath + ":" +
						element.attributeValue("line-number")));
		}

		String classType = PoshiRunnerGetterUtil.getClassTypeFromFilePath(
			filePath);

		if (classType.equals("function")) {
			List possibleAttributeNames = Arrays.asList(
				"default", "line-number", "summary", "summary-ignore");

			validatePossibleAttributeNames(
				element, possibleAttributeNames, filePath);
			validateRequiredAttributeNames(
				element, Arrays.asList("default"), filePath);
		}
		else if (classType.equals("macro")) {
			validateHasNoAttributes(element, filePath);
		}
		else if (classType.equals("testcase")) {
			List possibleAttributeNames = Arrays.asList(
				"component-name", "extends", "ignore", "ignore-command-names",
				"line-number");

			validatePossibleAttributeNames(
				element, possibleAttributeNames, filePath);
			validateRequiredAttributeNames(
				element, Arrays.asList("component-name"), filePath);
		}
	}

	protected static void validateElementName(
		Element element, List possibleElementNames, String filePath) {

		if (!possibleElementNames.contains(element.getName())) {
			_exceptions.add(
				new Exception(
					"Missing " + possibleElementNames + " element\n" +
						filePath + ":" +
							element.attributeValue("line-number")));
		}
	}

	protected static void validateElseElement(
		Element element, String filePath) {

		List elseElements = element.elements("else");

		if (elseElements.size() > 1) {
			_exceptions.add(
				new Exception(
					"Too many else elements\n" + filePath + ":" +
						element.attributeValue("line-number")));
		}

		if (!elseElements.isEmpty()) {
			Element elseElement = elseElements.get(0);

			parseElements(elseElement, filePath);
		}
	}

	protected static void validateElseIfElement(
		Element element, String filePath) {

		validateHasChildElements(element, filePath);
		validateHasNoAttributes(element, filePath);
		validateNumberOfChildElements(element, 2, filePath);
		validateThenElement(element, filePath);

		List childElements = element.elements();

		List conditionTags = Arrays.asList(
			"and", "condition", "contains", "equals", "isset", "not", "or");

		Element conditionElement = childElements.get(0);

		String conditionElementName = conditionElement.getName();

		if (conditionTags.contains(conditionElementName)) {
			validateConditionElement(conditionElement, filePath);
		}
		else {
			_exceptions.add(
				new Exception(
					"Invalid " + conditionElementName + " element\n" +
						filePath + ":" +
							element.attributeValue("line-number")));
		}

		Element thenElement = element.element("then");

		validateHasChildElements(thenElement, filePath);
		validateHasNoAttributes(thenElement, filePath);

		parseElements(thenElement, filePath);
	}

	protected static void validateExecuteElement(
		Element element, String filePath) {

		List multiplePrimaryAttributeNames = null;

		List primaryAttributeNames = Arrays.asList(
			"function", "groovy-script", "macro", "macro-desktop",
			"macro-mobile", "method", "selenium", "test-case");

		if (filePath.endsWith(".function")) {
			primaryAttributeNames = Arrays.asList("function", "selenium");
		}
		else if (filePath.endsWith(".macro")) {
			multiplePrimaryAttributeNames = Arrays.asList(
				"macro-desktop", "macro-mobile");

			primaryAttributeNames = Arrays.asList(
				"function", "groovy-script", "macro", "macro-desktop",
				"macro-mobile", "method");
		}
		else if (filePath.endsWith(".testcase")) {
			multiplePrimaryAttributeNames = Arrays.asList(
				"macro-desktop", "macro-mobile");

			primaryAttributeNames = Arrays.asList(
				"function", "groovy-script", "macro", "macro-desktop",
				"macro-mobile", "method", "test-case");
		}

		String primaryAttributeName = getPrimaryAttributeName(
			element, multiplePrimaryAttributeNames, primaryAttributeNames,
			filePath);

		if (primaryAttributeName == null) {
			return;
		}

		if (primaryAttributeName.equals("function")) {
			List possibleAttributeNames = Arrays.asList(
				"function", "line-number", "locator1", "locator2", "value1",
				"value2");

			validatePossibleAttributeNames(
				element, possibleAttributeNames, filePath);

			validateFunctionContext(element, filePath);
		}
		else if (primaryAttributeName.equals("groovy-script")) {
			List possibleAttributeNames = Arrays.asList(
				"groovy-script", "line-number", "return");

			validatePossibleAttributeNames(
				element, possibleAttributeNames, filePath);
		}
		else if (primaryAttributeName.equals("macro")) {
			List possibleAttributeNames = Arrays.asList(
				"line-number", "macro");

			validatePossibleAttributeNames(
				element, possibleAttributeNames, filePath);

			validateMacroContext(element, "macro", filePath);
		}
		else if (primaryAttributeName.equals("macro-desktop")) {
			List possibleAttributeNames = Arrays.asList(
				"line-number", "macro-desktop", "macro-mobile");

			validatePossibleAttributeNames(
				element, possibleAttributeNames, filePath);

			validateMacroContext(element, "macro-desktop", filePath);
		}
		else if (primaryAttributeName.equals("macro-mobile")) {
			List possibleAttributeNames = Arrays.asList(
				"line-number", "macro-desktop", "macro-mobile");

			validatePossibleAttributeNames(
				element, possibleAttributeNames, filePath);

			validateMacroContext(element, "macro-mobile", filePath);
		}
		else if (primaryAttributeName.equals("method")) {
			validateMethodExecuteElement(element, filePath);
		}
		else if (primaryAttributeName.equals("selenium")) {
			List possibleAttributeNames = Arrays.asList(
				"argument1", "argument2", "line-number", "selenium");

			validatePossibleAttributeNames(
				element, possibleAttributeNames, filePath);
		}
		else if (primaryAttributeName.equals("test-case")) {
			List possibleAttributeNames = Arrays.asList(
				"line-number", "test-case");

			validatePossibleAttributeNames(
				element, possibleAttributeNames, filePath);

			validateTestCaseContext(element, filePath);
		}

		List childElements = element.elements();

		if (!childElements.isEmpty()) {
			primaryAttributeNames = Arrays.asList(
				"function", "groovy-script", "macro", "macro-desktop",
				"macro-mobile", "method", "selenium", "test-case");

			validateHasPrimaryAttributeName(
				element, multiplePrimaryAttributeNames, primaryAttributeNames,
				filePath);

			List possibleChildElementNames = Arrays.asList(
				"arg", "return", "var");

			for (Element childElement : childElements) {
				String childElementName = childElement.getName();

				if (!possibleChildElementNames.contains(childElementName)) {
					_exceptions.add(
						new Exception(
							"Invalid child element\n" + filePath + ":" +
								childElement.attributeValue("line-number")));
				}
			}

			List argElements = element.elements("arg");

			for (Element argElement : argElements) {
				validateArgElement(argElement, filePath);
			}

			List returnElements = element.elements("return");

			for (Element returnElement : returnElements) {
				if (primaryAttributeName.equals("macro")) {
					validateExecuteReturnMacroElement(returnElement, filePath);

					validateMacroReturnsAttribute(
						element, "macro", returnElement, filePath);
				}
				else if (primaryAttributeName.equals("method")) {
					validateExecuteReturnMethodElement(returnElement, filePath);
				}
			}

			List varElements = element.elements("var");

			for (Element varElement : varElements) {
				validateVarElement(varElement, filePath);
			}
		}
	}

	protected static void validateExecuteReturnMacroElement(
		Element element, String filePath) {

		List attributeNames = Arrays.asList(
			"from", "line-number", "name");

		validateHasNoChildElements(element, filePath);
		validatePossibleAttributeNames(element, attributeNames, filePath);
		validateRequiredAttributeNames(element, attributeNames, filePath);
	}

	protected static void validateExecuteReturnMethodElement(
		Element element, String filePath) {

		List attributeNames = Arrays.asList("line-number", "name");

		validateHasNoChildElements(element, filePath);
		validatePossibleAttributeNames(element, attributeNames, filePath);
		validateRequiredAttributeNames(element, attributeNames, filePath);
	}

	protected static void validateForElement(Element element, String filePath) {
		List attributeNames = Arrays.asList(
			"line-number", "list", "param");

		validateHasChildElements(element, filePath);
		validatePossibleAttributeNames(element, attributeNames, filePath);
		validateRequiredAttributeNames(element, attributeNames, filePath);

		parseElements(element, filePath);
	}

	protected static void validateFunctionContext(
		Element element, String filePath) {

		String function = element.attributeValue("function");

		validateClassCommandName(element, function, "function", filePath);

		String className =
			PoshiRunnerGetterUtil.getClassNameFromClassCommandName(function);

		int locatorCount = PoshiRunnerContext.getFunctionLocatorCount(
			className);

		for (int i = 0; i < locatorCount; i++) {
			String locator = element.attributeValue("locator" + (i + 1));

			if (locator != null) {
				Matcher matcher = _pattern.matcher(locator);

				if (!locator.contains("#") || matcher.find()) {
					continue;
				}

				String pathName =
					PoshiRunnerGetterUtil.getClassNameFromClassCommandName(
						locator);

				if (!PoshiRunnerContext.isRootElement("path#" + pathName)) {
					_exceptions.add(
						new Exception(
							"Invalid path name " + pathName + "\n" + filePath +
								":" + element.attributeValue("line-number")));
				}
				else if (!PoshiRunnerContext.isPathLocator(locator)) {
					_exceptions.add(
						new Exception(
							"Invalid path locator " + locator + "\n" +
								filePath + ":" +
									element.attributeValue("line-number")));
				}
			}
		}
	}

	protected static void validateFunctionFile(
		Element element, String filePath) {

		validateDefinitionElement(element, filePath);
		validateHasChildElements(element, filePath);
		validateRequiredChildElementNames(
			element, Arrays.asList("command"), filePath);

		List childElements = element.elements();

		for (Element childElement : childElements) {
			validateCommandElement(childElement, filePath);
			validateHasChildElements(childElement, filePath);

			parseElements(childElement, filePath);
		}
	}

	protected static void validateHasChildElements(
		Element element, String filePath) {

		List childElements = element.elements();

		if (childElements.isEmpty()) {
			_exceptions.add(
				new Exception(
					"Missing child elements\n" + filePath + ":" +
						element.attributeValue("line-number")));
		}
	}

	protected static void validateHasMultiplePrimaryAttributeNames(
		Element element, List attributeNames,
		List multiplePrimaryAttributeNames, String filePath) {

		if (!multiplePrimaryAttributeNames.equals(attributeNames)) {
			_exceptions.add(
				new Exception(
					"Too many attributes\n" + filePath + ":" +
						element.attributeValue("line-number")));
		}
	}

	protected static void validateHasNoAttributes(
		Element element, String filePath) {

		List attributes = element.attributes();

		if (!attributes.isEmpty()) {
			for (Attribute attribute : attributes) {
				String attributeName = attribute.getName();

				if (attributeName.equals("line-number")) {
					continue;
				}

				_exceptions.add(
					new Exception(
						"Invalid " + attributeName + " attribute\n" + filePath +
							":" + element.attributeValue("line-number")));
			}
		}
	}

	protected static void validateHasNoChildElements(
		Element element, String filePath) {

		List childElements = element.elements();

		if (!childElements.isEmpty()) {
			_exceptions.add(
				new Exception(
					"Invalid child elements\n" + filePath + ":" +
						element.attributeValue("line-number")));
		}
	}

	protected static void validateHasPrimaryAttributeName(
		Element element, List multiplePrimaryAttributeNames,
		List primaryAttributeNames, String filePath) {

		List attributeNames = new ArrayList<>();

		for (String primaryAttributeName : primaryAttributeNames) {
			if (Validator.isNotNull(
					element.attributeValue(primaryAttributeName))) {

				attributeNames.add(primaryAttributeName);
			}
		}

		if (attributeNames.size() < 1) {
			_exceptions.add(
				new Exception(
					"Invalid or missing attribute\n" + filePath + ":" +
						element.attributeValue("line-number")));
		}
		else if (attributeNames.size() > 1) {
			if (Validator.isNull(multiplePrimaryAttributeNames)) {
				_exceptions.add(
					new Exception(
						"Too many attributes\n" + filePath + ":" +
							element.attributeValue("line-number")));
			}
			else {
				validateHasMultiplePrimaryAttributeNames(
					element, attributeNames, multiplePrimaryAttributeNames,
					filePath);
			}
		}
	}

	protected static void validateHasPrimaryAttributeName(
		Element element, List primaryAttributeNames, String filePath) {

		validateHasPrimaryAttributeName(
			element, null, primaryAttributeNames, filePath);
	}

	protected static void validateHasRequiredPropertyElements(
		Element element, String filePath) {

		List requiredPropertyNames = new ArrayList(
			PoshiRunnerContext.getTestCaseRequiredPropertyNames());

		List propertyElements = element.elements("property");

		for (Element propertyElement : propertyElements) {
			validatePropertyElement(propertyElement, filePath);

			String propertyName = propertyElement.attributeValue("name");

			if (requiredPropertyNames.contains(propertyName)) {
				requiredPropertyNames.remove(propertyName);

				String testCaseAvailablePropertyValues = PropsUtil.get(
					"test.case.available.property.values[" + propertyName +
						"]");

				if (Validator.isNotNull(testCaseAvailablePropertyValues)) {
					List possiblePropertyValues = Arrays.asList(
						StringUtil.split(testCaseAvailablePropertyValues));

					validatePossiblePropertyValues(
						propertyElement, possiblePropertyValues, filePath);
				}
			}
		}

		if (!requiredPropertyNames.isEmpty()) {
			_exceptions.add(
				new Exception(
					"Missing required properties " + requiredPropertyNames +
						"\n" + filePath));
		}
	}

	protected static void validateIfElement(Element element, String filePath) {
		validateHasChildElements(element, filePath);
		validateHasNoAttributes(element, filePath);

		String fileName = filePath.substring(filePath.lastIndexOf(".") + 1);

		List childElements = element.elements();

		List conditionTags = Arrays.asList(
			"and", "condition", "contains", "equals", "isset", "not", "or");

		if (fileName.equals("function")) {
			conditionTags = Arrays.asList(
				"and", "condition", "contains", "not", "or");
		}

		validateElseElement(element, filePath);
		validateThenElement(element, filePath);

		for (int i = 0; i < childElements.size(); i++) {
			Element childElement = childElements.get(i);

			String childElementName = childElement.getName();

			if (i == 0) {
				if (conditionTags.contains(childElementName)) {
					validateConditionElement(childElement, filePath);
				}
				else {
					_exceptions.add(
						new Exception(
							"Missing or invalid if condition element\n" +
								filePath + ":" +
									element.attributeValue("line-number")));
				}
			}
			else if (childElementName.equals("else")) {
				validateHasChildElements(childElement, filePath);
				validateHasNoAttributes(childElement, filePath);

				parseElements(childElement, filePath);
			}
			else if (childElementName.equals("elseif")) {
				validateHasChildElements(childElement, filePath);
				validateHasNoAttributes(childElement, filePath);

				validateElseIfElement(childElement, filePath);
			}
			else if (childElementName.equals("then")) {
				validateHasChildElements(childElement, filePath);
				validateHasNoAttributes(childElement, filePath);

				parseElements(childElement, filePath);
			}
			else {
				_exceptions.add(
					new Exception(
						"Invalid " + childElementName + " element\n" +
							filePath + ":" +
								childElement.attributeValue("line-number")));
			}
		}
	}

	protected static void validateMacroContext(
		Element element, String macroType, String filePath) {

		validateClassCommandName(
			element, element.attributeValue(macroType), "macro", filePath);
	}

	protected static void validateMacroFile(Element element, String filePath) {
		validateDefinitionElement(element, filePath);
		validateHasChildElements(element, filePath);
		validateRequiredChildElementName(element, "command", filePath);

		List childElements = element.elements();

		List possibleTagElementNames = Arrays.asList("command", "var");

		for (Element childElement : childElements) {
			String childElementName = childElement.getName();

			if (!possibleTagElementNames.contains(childElementName)) {
				_exceptions.add(
					new Exception(
						"Invalid " + childElementName + " element\n" +
							filePath + ":" +
								childElement.attributeValue("line-number")));
			}

			if (childElementName.equals("command")) {
				validateCommandElement(childElement, filePath);
				validateHasChildElements(childElement, filePath);

				parseElements(childElement, filePath);
			}
			else if (childElementName.equals("var")) {
				validateVarElement(childElement, filePath);
			}
		}
	}

	protected static void validateMacroReturnsAttribute(
		Element element, String macroType, Element returnElement,
		String filePath) {

		String classCommandName = element.attributeValue(macroType);

		List returns = PoshiRunnerContext.getMacroCommandReturns(
			classCommandName);

		String returnVariable = returnElement.attributeValue("from");

		if (!returns.contains(returnVariable)) {
			_exceptions.add(
				new Exception(
					returnVariable + " not specified as a return variable\n" +
						filePath + ":" +
							element.attributeValue("line-number")));
		}
	}

	protected static void validateMessageElement(
		Element element, String filePath) {

		List possibleAttributeNames = Arrays.asList(
			"line-number", "message");

		validateHasNoChildElements(element, filePath);
		validatePossibleAttributeNames(
			element, possibleAttributeNames, filePath);

		if ((element.attributeValue("message") == null) &&
			Validator.isNull(element.getText())) {

			_exceptions.add(
				new Exception(
					"Missing message attribute\n" + filePath + ":" +
						element.attributeValue("line-number")));
		}
	}

	protected static void validateMethodExecuteElement(
		Element element, String filePath) {

		String className = element.attributeValue("class");

		Class clazz = null;

		try {
			clazz = Class.forName(className);
		}
		catch (Exception e) {
			_exceptions.add(
				new Exception(
					"Unable to find class " + className + "\n" + filePath +
						":" + element.attributeValue("line-number")));

			return;
		}

		String methodName = element.attributeValue("method");

		List possibleMethods = new ArrayList<>();

		List completeMethods = Arrays.asList(clazz.getMethods());

		for (Method possibleMethod : completeMethods) {
			String possibleMethodName = possibleMethod.getName();

			if (methodName.equals(possibleMethodName)) {
				possibleMethods.add(possibleMethod);
			}
		}

		if (possibleMethods.isEmpty()) {
			_exceptions.add(
				new Exception(
					"Unable to find method " + className + "#" + methodName +
						"\n" + filePath + ":" +
							element.attributeValue("line-number")));

			return;
		}

		List argElements = new ArrayList<>(element.elements("arg"));

		Class[] parameterTypes = new Class[argElements.size()];

		for (int i = 0; i < argElements.size(); i++) {
			parameterTypes[i] = String.class;
		}

		try {
			clazz.getMethod(methodName, parameterTypes);
		}
		catch (Exception e) {
			_exceptions.add(
				new Exception(
					"Mismatched argument in method " + className + "#" +
						methodName + "\n" + filePath + ":" +
							element.attributeValue("line-number")));
		}
	}

	protected static void validateNumberOfAttributes(
		Element element, int number, String filePath) {

		List attributes = element.attributes();

		if (attributes.isEmpty()) {
			_exceptions.add(
				new Exception(
					"Missing attributes\n" + filePath + ":" +
						element.attributeValue("line-number")));
		}
		else if (attributes.size() > number) {
			_exceptions.add(
				new Exception(
					"Too many attributes\n" + filePath + ":" +
						element.attributeValue("line-number")));
		}
		else if (attributes.size() < number) {
			_exceptions.add(
				new Exception(
					"Too few attributes\n" + filePath + ":" +
						element.attributeValue("line-number")));
		}
	}

	protected static void validateNumberOfChildElements(
		Element element, int number, String filePath) {

		List childElements = element.elements();

		if (childElements.isEmpty()) {
			_exceptions.add(
				new Exception(
					"Missing child elements\n" + filePath + ":" +
						element.attributeValue("line-number")));
		}
		else if (childElements.size() > number) {
			_exceptions.add(
				new Exception(
					"Too many child elements\n" + filePath + ":" +
						element.attributeValue("line-number")));
		}
		else if (childElements.size() < number) {
			_exceptions.add(
				new Exception(
					"Too few child elements\n" + filePath + ":" +
						element.attributeValue("line-number")));
		}
	}

	protected static void validatePathFile(Element element, String filePath) {
		String className = PoshiRunnerGetterUtil.getClassNameFromFilePath(
			filePath);
		String rootElementName = element.getName();

		if (!Objects.equals(rootElementName, "html")) {
			_exceptions.add(
				new Exception(
					"Invalid " + rootElementName + " element\n" + filePath +
						":" + element.attributeValue("line-number")));
		}

		validateHasChildElements(element, filePath);
		validateNumberOfChildElements(element, 2, filePath);
		validateRequiredChildElementNames(
			element, Arrays.asList("body", "head"), filePath);

		Element bodyElement = element.element("body");

		validateHasChildElements(bodyElement, filePath);
		validateNumberOfChildElements(bodyElement, 1, filePath);
		validateRequiredChildElementName(bodyElement, "table", filePath);

		Element tableElement = bodyElement.element("table");

		List requiredTableAttributeNames = Arrays.asList(
			"border", "cellpadding", "cellspacing", "line-number");

		validateHasChildElements(tableElement, filePath);
		validateNumberOfChildElements(tableElement, 2, filePath);
		validateRequiredAttributeNames(
			tableElement, requiredTableAttributeNames, filePath);
		validateRequiredChildElementNames(
			tableElement, Arrays.asList("tbody", "thead"), filePath);

		Element tBodyElement = tableElement.element("tbody");

		List trElements = tBodyElement.elements();

		if (Validator.isNotNull(trElements)) {
			for (Element trElement : trElements) {
				validateHasChildElements(trElement, filePath);
				validateNumberOfChildElements(trElement, 3, filePath);
				validateRequiredChildElementName(trElement, "td", filePath);

				List tdElements = trElement.elements();

				Element locatorElement = tdElements.get(1);

				String locator = locatorElement.getText();

				Element locatorKeyElement = tdElements.get(0);

				String locatorKey = locatorKeyElement.getText();

				if (Validator.isNull(locator) && Validator.isNull(locatorKey)) {
					continue;
				}
				else if (Validator.isNotNull(locator) &&
						 Validator.isNotNull(locatorKey)) {

					continue;
				}

				_exceptions.add(
					new Exception(
						"Missing locator\n" + filePath + ":" +
							trElement.attributeValue("line-number")));
			}
		}

		Element theadElement = tableElement.element("thead");

		validateHasChildElements(theadElement, filePath);
		validateNumberOfChildElements(theadElement, 1, filePath);
		validateRequiredChildElementName(theadElement, "tr", filePath);

		Element trElement = theadElement.element("tr");

		validateHasChildElements(trElement, filePath);
		validateNumberOfChildElements(trElement, 1, filePath);
		validateRequiredChildElementName(trElement, "td", filePath);

		Element tdElement = trElement.element("td");

		validateRequiredAttributeNames(
			tdElement, Arrays.asList("colspan", "rowspan"), filePath);

		String theadClassName = tdElement.getText();

		if (Validator.isNull(theadClassName)) {
			_exceptions.add(
				new Exception(
					"Missing thead class name\n" + filePath + ":" +
						trElement.attributeValue("line-number")));
		}
		else if (!Objects.equals(theadClassName, className)) {
			_exceptions.add(
				new Exception(
					"Thead class name does not match file name\n" + filePath +
						":" + trElement.attributeValue("line-number")));
		}

		Element headElement = element.element("head");

		validateHasChildElements(headElement, filePath);
		validateNumberOfChildElements(headElement, 1, filePath);
		validateRequiredChildElementName(headElement, "title", filePath);

		Element titleElement = headElement.element("title");

		if (!Objects.equals(titleElement.getText(), className)) {
			_exceptions.add(
				new Exception(
					"File name and title are different\n" + filePath + ":" +
						titleElement.attributeValue("line-number")));
		}
	}

	protected static void validatePossibleAttributeNames(
		Element element, List possibleAttributeNames, String filePath) {

		List attributes = element.attributes();

		for (Attribute attribute : attributes) {
			String attributeName = attribute.getName();

			if (!possibleAttributeNames.contains(attributeName)) {
				_exceptions.add(
					new Exception(
						"Invalid " + attributeName + " attribute\n" + filePath +
							":" + element.attributeValue("line-number")));
			}
		}
	}

	protected static void validatePossiblePropertyValues(
		Element element, List possiblePropertyValues, String filePath) {

		List propertyValues = Arrays.asList(
			StringUtil.split(element.attributeValue("value")));

		for (String propertyValue : propertyValues) {
			if (!possiblePropertyValues.contains(propertyValue.trim())) {
				_exceptions.add(
					new Exception(
						"Invalid " + propertyValue.trim() +
							" property value\n" + filePath + ":" +
								element.attributeValue("line-number")));
			}
		}
	}

	protected static void validatePropertyElement(
		Element element, String filePath) {

		List attributeNames = Arrays.asList(
			"line-number", "name", "value");

		validateHasNoChildElements(element, filePath);
		validatePossibleAttributeNames(element, attributeNames, filePath);
		validateRequiredAttributeNames(element, attributeNames, filePath);

		List testCaseAvailablePropertyNames =
			PoshiRunnerContext.getTestCaseAvailablePropertyNames();

		String propertyName = element.attributeValue("name");

		if (!testCaseAvailablePropertyNames.contains(propertyName)) {
			_exceptions.add(
				new Exception(
					"Invalid property name " + propertyName + "\n" + filePath +
						":" + element.attributeValue("line-number")));
		}
	}

	protected static void validateRequiredAttributeNames(
		Element element, List requiredAttributeNames, String filePath) {

		for (String requiredAttributeName : requiredAttributeNames) {
			if (element.attributeValue(requiredAttributeName) == null) {
				_exceptions.add(
					new Exception(
						"Missing " + requiredAttributeName + " attribute\n" +
							filePath + ":" +
								element.attributeValue("line-number")));
			}
		}
	}

	protected static void validateRequiredChildElementName(
		Element element, String requiredElementName, String filePath) {

		boolean found = false;

		List childElements = element.elements();

		for (Element childElement : childElements) {
			if (Objects.equals(childElement.getName(), requiredElementName)) {
				found = true;

				break;
			}
		}

		if (!found) {
			_exceptions.add(
				new Exception(
					"Missing required " + requiredElementName +
						" child element\n" + filePath + ":" +
							element.attributeValue("line-number")));
		}
	}

	protected static void validateRequiredChildElementNames(
		Element element, List requiredElementNames, String filePath) {

		for (String requiredElementName : requiredElementNames) {
			validateRequiredChildElementName(
				element, requiredElementName, filePath);
		}
	}

	protected static void validateTakeScreenshotElement(
		Element element, String filePath) {

		validateHasNoAttributes(element, filePath);
		validateHasNoChildElements(element, filePath);
	}

	protected static void validateTaskElement(
		Element element, String filePath) {

		List possibleAttributeNames = Arrays.asList(
			"line-number", "macro-summary", "summary");

		validateHasChildElements(element, filePath);
		validatePossibleAttributeNames(
			element, possibleAttributeNames, filePath);

		List primaryAttributeNames = Arrays.asList(
			"macro-summary", "summary");

		validateHasPrimaryAttributeName(
			element, primaryAttributeNames, filePath);

		parseElements(element, filePath);
	}

	protected static void validateTestCaseContext(
		Element element, String filePath) {

		String testName = element.attributeValue("test-case");

		String className =
			PoshiRunnerGetterUtil.getClassNameFromClassCommandName(testName);

		String commandName =
			PoshiRunnerGetterUtil.getCommandNameFromClassCommandName(testName);

		if (className.equals("super")) {
			className = PoshiRunnerGetterUtil.getExtendedTestCaseName(filePath);
		}

		validateTestName(
			className + "#" + commandName,
			filePath + ":" + element.attributeValue("line-number"));
	}

	protected static void validateTestCaseFile(
		Element element, String filePath) {

		validateDefinitionElement(element, filePath);

		List childElements = element.elements();

		if (Validator.isNull(element.attributeValue("extends"))) {
			validateHasChildElements(element, filePath);
			validateRequiredChildElementName(element, "command", filePath);
		}

		validateHasRequiredPropertyElements(element, filePath);

		List possibleTagElementNames = Arrays.asList(
			"command", "property", "set-up", "tear-down", "var");

		List propertyNames = new ArrayList<>();

		for (Element childElement : childElements) {
			String childElementName = childElement.getName();

			if (!possibleTagElementNames.contains(childElementName)) {
				_exceptions.add(
					new Exception(
						"Invalid " + childElementName + " element\n" +
							filePath + ":" +
								childElement.attributeValue("line-number")));
			}

			if (childElementName.equals("command")) {
				List possibleAttributeNames = Arrays.asList(
					"description", "known-issues", "line-number", "name",
					"priority");

				validateHasChildElements(childElement, filePath);
				validatePossibleAttributeNames(
					childElement, possibleAttributeNames, filePath);
				validateRequiredAttributeNames(
					childElement, Arrays.asList("name"), filePath);

				parseElements(childElement, filePath);
			}
			else if (childElementName.equals("property")) {
				validatePropertyElement(childElement, filePath);

				String propertyName = childElement.attributeValue("name");

				if (!propertyNames.contains(propertyName)) {
					propertyNames.add(propertyName);
				}
				else {
					_exceptions.add(
						new Exception(
							"Duplicate property name " + propertyName + "\n" +
								filePath + ":" +
									childElement.attributeValue(
										"line-number")));
				}
			}
			else if (childElementName.equals("set-up") ||
					 childElementName.equals("tear-down")) {

				validateHasChildElements(childElement, filePath);
				validateHasNoAttributes(childElement, filePath);

				parseElements(childElement, filePath);
			}
			else if (childElementName.equals("var")) {
				validateVarElement(childElement, filePath);
			}
		}
	}

	protected static void validateTestName(String testName) {
		validateTestName(testName, "");
	}

	protected static void validateTestName(
		String testName, String filePathLineNumber) {

		String className =
			PoshiRunnerGetterUtil.getClassNameFromClassCommandName(testName);

		if (!PoshiRunnerContext.isRootElement("test-case#" + className)) {
			_exceptions.add(
				new Exception(
					"Invalid test case class " + className + "\n" +
						filePathLineNumber));
		}
		else if (testName.contains("#")) {
			String commandElementKey = "test-case#" + testName;

			if (!PoshiRunnerContext.isCommandElement(commandElementKey)) {
				String commandName =
					PoshiRunnerGetterUtil.getCommandNameFromClassCommandName(
						testName);

				_exceptions.add(
					new Exception(
						"Invalid test case command " + commandName + "\n" +
							filePathLineNumber));
			}
		}
	}

	protected static void validateThenElement(
		Element element, String filePath) {

		List thenElements = element.elements("then");

		if (thenElements.isEmpty()) {
			_exceptions.add(
				new Exception(
					"Missing then element\n" + filePath + ":" +
						element.attributeValue("line-number")));
		}
		else if (thenElements.size() > 1) {
			_exceptions.add(
				new Exception(
					"Too many then elements\n" + filePath + ":" +
						element.attributeValue("line-number")));
		}
	}

	protected static void validateVarElement(Element element, String filePath) {
		validateHasNoChildElements(element, filePath);
		validateRequiredAttributeNames(
			element, Arrays.asList("name"), filePath);

		List attributes = element.attributes();

		if (attributes.size() <= 2) {
			if (Validator.isNull(element.getText())) {
				_exceptions.add(
					new Exception(
						"Missing value attribute\n" + filePath + ":" +
							element.attributeValue("line-number")));
			}
		}

		List possibleAttributeNames = new ArrayList<>();

		possibleAttributeNames.addAll(
			Arrays.asList(
				"attribute", "group", "input", "line-number", "locator",
				"method", "name", "pattern", "property-value", "value"));

		Element parentElement = element.getParent();

		if (parentElement != null) {
			String parentElementName = parentElement.getName();

			if (filePath.contains(".testcase") &&
				parentElementName.equals("definition")) {

				possibleAttributeNames.add("static");
			}
		}

		validatePossibleAttributeNames(
			element, possibleAttributeNames, filePath);

		if (Validator.isNotNull(element.attributeValue("attribute"))) {
			List attributeNames = Arrays.asList(
				"attribute", "line-number", "locator", "name");

			validatePossibleAttributeNames(element, attributeNames, filePath);
			validateRequiredAttributeNames(element, attributeNames, filePath);
		}
		else if (Validator.isNotNull(element.attributeValue("group")) ||
				 Validator.isNotNull(element.attributeValue("input")) ||
				 Validator.isNotNull(element.attributeValue("pattern"))) {

			List attributeNames = Arrays.asList(
				"group", "line-number", "input", "name", "pattern");

			validatePossibleAttributeNames(element, attributeNames, filePath);
			validateRequiredAttributeNames(element, attributeNames, filePath);
		}
		else if (Validator.isNotNull(element.attributeValue("locator")) ||
				 Validator.isNotNull(element.attributeValue("method")) ||
				 Validator.isNotNull(
					 element.attributeValue("property-value")) ||
				 Validator.isNotNull(element.attributeValue("var"))) {

			validateNumberOfAttributes(element, 3, filePath);
		}
	}

	protected static void validateWhileElement(
		Element element, String filePath) {

		validateHasChildElements(element, filePath);
		validatePossibleAttributeNames(
			element, Arrays.asList("line-number", "max-iterations"), filePath);
		validateThenElement(element, filePath);

		List conditionTags = Arrays.asList(
			"and", "condition", "contains", "equals", "isset", "not", "or");

		List childElements = element.elements();

		for (int i = 0; i < childElements.size(); i++) {
			Element childElement = childElements.get(i);

			String childElementName = childElement.getName();

			if (i == 0) {
				if (conditionTags.contains(childElementName)) {
					validateConditionElement(childElement, filePath);
				}
				else {
					_exceptions.add(
						new Exception(
							"Missing while condition element\n" + filePath +
								":" + element.attributeValue("line-number")));
				}
			}
			else if (childElementName.equals("then")) {
				validateHasChildElements(childElement, filePath);
				validateHasNoAttributes(childElement, filePath);

				parseElements(childElement, filePath);
			}
			else {
				_exceptions.add(
					new Exception(
						"Invalid " + childElementName + " element\n" +
							filePath + ":" +
								childElement.attributeValue("line-number")));
			}
		}
	}

	private static void _throwExceptions() throws Exception {
		StringBuilder sb = new StringBuilder();

		sb.append(Integer.toString(_exceptions.size()));
		sb.append(" errors in POSHI\n\n\n");

		for (Exception exception : _exceptions) {
			sb.append(exception.getMessage());
			sb.append("\n\n");
		}

		System.out.println(sb.toString());

		throw new Exception();
	}

	private static final String _TEST_BASE_DIR_NAME =
		PoshiRunnerGetterUtil.getCanonicalPath(PropsValues.TEST_BASE_DIR_NAME);

	private static final Set _exceptions = new HashSet<>();
	private static final Pattern _pattern = Pattern.compile("\\$\\{([^}]*)\\}");

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy