/* * Copyright 2004-2016 EPAM Systems * * This file is part of JDI project. * * JDI 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 3 of the License, or * (at your option) any later version. * * JDI is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; * without even the implied warranty ofMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with JDI. If not, see <http://www.gnu.org/licenses/>. */ package com.epam.web.matcher.base; import com.epam.commons.LinqUtils; import com.epam.commons.Timer; import com.epam.commons.linqinterfaces.JAction; import com.epam.commons.linqinterfaces.JFuncREx; import com.epam.commons.map.MapArray; import org.slf4j.Logger; import java.util.Collection; import java.util.Map; import java.util.function.BooleanSupplier; import java.util.function.Consumer; import java.util.function.Supplier; import static com.epam.commons.LinqUtils.first; import static com.epam.commons.LinqUtils.select; import static com.epam.commons.PrintUtils.print; import static com.epam.commons.ReflectionUtils.isInterface; import static com.epam.web.matcher.base.DoScreen.NO_SCREEN; import static com.epam.web.matcher.base.PrintUtils.objToSetValue; import static com.epam.web.matcher.base.PrintUtils.printObjectAsArray; import static java.lang.String.format; import static java.lang.reflect.Array.get; import static java.lang.reflect.Array.getLength; import static java.util.Arrays.asList; import static org.slf4j.LoggerFactory.getLogger; /** * Created by Roman_Iovlev on 6/9/2015. */ public abstract class BaseMatcher implements IAsserter, IChecker { private static Logger logger = getLogger("JDI Logger"); public void setLogger(Logger logger) { BaseMatcher.logger = logger; } private static long waitTimeout = 0; private static DoScreen defaultDoScreenType = NO_SCREEN; private static String FOUND = "FOUND"; private DoScreen doScreenshot = defaultDoScreenType; private String checkMessage = ""; private boolean ignoreCase; private boolean isListCheck; private long timeout() { return waitTimeout; } public BaseMatcher() { } public BaseMatcher(String checkMessage) { this.checkMessage = getCheckMessage(checkMessage); } public static void setDefaultTimeout(long timeout) { waitTimeout = timeout; } public static void setDefaultDoScreenType(DoScreen doScreen) { defaultDoScreenType = doScreen; } protected abstract Consumer<String> throwFail(); public BaseMatcher doScreenshot(DoScreen doScreenshot) { this.doScreenshot = doScreenshot; return this; } public BaseMatcher doScreenshot() { return doScreenshot(DoScreen.DO_SCREEN_ALWAYS); } public BaseMatcher ignoreCase() { this.ignoreCase = true; return this; } public BaseMatcher setWait(int timeoutSec) { waitTimeout = timeoutSec * 1000L; return this; } private String getCheckMessage(String checkMessage) { if (checkMessage == null || checkMessage.equals("")) return ""; String firstWord = checkMessage.split(" ")[0]; return (!firstWord.equalsIgnoreCase("check") || firstWord.equalsIgnoreCase("verify")) ? "Check " + checkMessage : checkMessage; } private void assertAction(String defaultMessage, Boolean result, String failMessage) { assertAction(defaultMessage, () -> result ? FOUND : "Check failed", failMessage, false); } private void waitAction(String defaultMessage, BooleanSupplier result, String failMessage) { assertAction(defaultMessage, () -> result.getAsBoolean() ? FOUND : "Check failed", failMessage, true); } protected String doScreenshotGetMessage() { return "Screenshots switched off"; } private void assertAction(String defaultMessage, Supplier<String> result, String failMessage, boolean wait) { if (!isListCheck && defaultMessage != null) logger.info(getBeforeMessage(defaultMessage)); if (!isListCheck && doScreenshot == DoScreen.DO_SCREEN_ALWAYS) logger.info(doScreenshotGetMessage()); String resultMessage = (wait) ? new Timer(timeout()).getResultByCondition(result::get, r -> r != null && r.equals(FOUND)) : result.get(); if (resultMessage == null) { assertException("Assert Failed by Timeout. Wait %s seconds", timeout() / 1000); return; } if (!resultMessage.equals(FOUND)) { if (doScreenshot == DoScreen.SCREEN_ON_FAIL) logger.info(doScreenshotGetMessage()); assertException(failMessage == null ? defaultMessage + " failed" : failMessage); } } private String getBeforeMessage(String defaultMessage) { return (checkMessage != null && !checkMessage.equals("")) ? checkMessage : defaultMessage; } // For Framework public RuntimeException exception(String failMessage, Object... args) { assertException(failMessage, args); return new RuntimeException(failMessage); } protected void assertException(String failMessage, Object... args) { String failMsg = args.length > 0 ? format(failMessage, args) : failMessage; if (doScreenshot == DoScreen.SCREEN_ON_FAIL) logger.info(doScreenshotGetMessage()); logger.error(failMsg); throwFail().accept(failMsg); } public <TResult> TResult silent(JFuncREx<TResult> func) { try { return func.invoke(); } catch (Exception ex) { throw exception(ex.getMessage()); } } // Asserts public <T> void areEquals(T actual, T expected, String failMessage) { boolean result; if (expected.getClass() == String.class) { String actualString = actual.toString(); result = ignoreCase ? actualString.equalsIgnoreCase((String) expected) : actualString.equals(expected); } else result = actual.equals(expected); assertAction(format("Check that '%s' equals to '%s'", actual, expected), result, failMessage); } public <T> void areEquals(T actual, T expected) { areEquals(actual, expected, null); } public void matches(String actual, String regEx, String failMessage) { boolean result = ignoreCase && actual.getClass() == String.class ? actual.toLowerCase().matches(regEx.toLowerCase()) : actual.matches(regEx); assertAction(format("Check that '%s' matches to regEx '%s'", actual, regEx), result, failMessage); } public void matches(String actual, String expected) { matches(actual, expected, null); } public void contains(String actual, String expected, String failMessage) { boolean result = ignoreCase && actual.getClass() == String.class ? actual.toLowerCase().contains(expected.toLowerCase()) : actual.contains(expected); assertAction(format("Check that '%s' contains '%s'", actual, expected), result, failMessage); } public void contains(String actual, String expected) { contains(actual, expected, null); } public void isTrue(Boolean condition, String failMessage) { assertAction(format("Check that condition '%s' is True", condition), condition, failMessage); } public void isTrue(Boolean condition) { isTrue(condition, null); } public void isFalse(Boolean condition, String failMessage) { assertAction(format("Check that condition '%s' is False", condition), !condition, failMessage); } public void throwException(String actionName, JAction action, Class<Exception> exceptionClass, String exceptionText) { try { action.invoke(); } catch (Exception ex) { if (exceptionClass != null) areEquals(ex.getClass(), exceptionClass); if (exceptionText != null) areEquals(ex.getMessage(), exceptionText); } throw exception("Action '%s' throws no exceptions. Expected (%s, %s)", exceptionClass == null ? "" : exceptionClass.getName(), exceptionText); } public void throwException(JAction action, Class<Exception> exceptionClass, String exceptionText) { throwException(!checkMessage.equals("") ? checkMessage : "Action", action, exceptionClass, exceptionText); } public void hasNoExceptions(String actionName, JAction action) { try { action.invoke(); } catch (Exception ex) { throw exception(actionName + " throws exception: " + ex.getMessage()); } } public void hasNoExceptions(JAction action) { hasNoExceptions(!checkMessage.equals("") ? checkMessage : "Action", action); } private boolean isObjEmpty(Object obj) { if (obj == null) return true; if (obj instanceof String) return obj.toString().equals(""); if (isInterface(obj.getClass(), Collection.class)) return ((Collection) obj).isEmpty(); return obj.getClass().isArray() && getLength(obj) == 0; } public void isEmpty(Object obj, String failMessage) { assertAction("Check that Object is empty", isObjEmpty(obj), failMessage); } public void isNotEmpty(Object obj, String failMessage) { assertAction("Check that Object is NOT empty", !isObjEmpty(obj), failMessage); } public <T> void areSame(T actual, T expected, String failMessage) { assertAction("Check that Objects are the same", actual == expected, failMessage); } public <T> void areDifferent(T actual, T expected, String failMessage) { assertAction("Check that Objects are different", actual != expected, failMessage); } public <T> void listEquals(Collection<T> actual, Collection<T> expected, String failMessage) { assertAction("Check that Collections are equal", () -> actual != null && expected != null && actual.size() == expected.size() ? FOUND : "listEquals failed because one of the Collections is null or empty", failMessage, false); assertAction(null, () -> { T notEqualElement = LinqUtils.first(actual, el -> !expected.contains(el)); return (notEqualElement != null) ? String.format("Collections '%s' and '%s' not equals at element '%s'", print(LinqUtils.select(actual, Object::toString)), print(LinqUtils.select(expected, Object::toString)), notEqualElement) : FOUND; }, failMessage, false); } private <T> void entityIncludeMap(Map<String, String> actual, T entity, String failMessage, boolean shouldEqual) { entityIncludeMapArray(MapArray.toMapArray(actual), entity, failMessage, shouldEqual); } private <T> void entityIncludeMapArray(MapArray<String, String> actual, T entity, String failMessage, boolean shouldEqual) { MapArray<String, String> expected = objToSetValue(entity).where((k, value) -> value != null); assertAction("Check that Collections are equal", () -> actual != null && expected != null && (!shouldEqual || actual.size() == expected.size()) ? FOUND : "listEquals failed because one of the Collections is null or empty", failMessage, false); assertAction(null, () -> { String notEqualElement = expected.first((name, value) -> actual.get(name).equals(value)); return (notEqualElement != null) ? String.format("Collections '%s' and '%s' not equals at element '%s'", print(select(actual, Object::toString)), print(select(expected, Object::toString)), notEqualElement) : FOUND; }, failMessage, false); } public <T> void entityIncludeMapArray(MapArray<String, String> actual, T entity, String failMessage) { entityIncludeMapArray(actual, entity, failMessage, false); } public <T> void entityEqualsToMapArray(MapArray<String, String> actual, T entity, String failMessage) { entityIncludeMapArray(actual, entity, failMessage, true); } public <T> void entityIncludeMap(Map<String, String> actual, T entity, String failMessage) { entityIncludeMap(actual, entity, failMessage, false); } public <T> void entityEqualsToMap(Map<String, String> actual, T entity, String failMessage) { entityIncludeMap(actual, entity, failMessage, true); } public <T> void arrayEquals(T actual, T expected, String failMessage) { assertAction("Check that Collections are equal", () -> actual != null && expected != null && actual.getClass().isArray() && expected.getClass().isArray() ? FOUND : "arrayEquals failed because one of the Objects is not Array or empty", failMessage, false); assertAction("Check that Collections are equal", () -> getLength(actual) == getLength(expected) ? FOUND : format("arrayEquals failed because arrays have different lengths: '%s' and '%s'", getLength(actual), getLength(expected)), failMessage, false); assertAction(null, () -> { for (int i = 0; i < getLength(actual); i++) if (!get(actual, i).equals(get(expected, i))) return String.format("Arrays not equals at index '%s'. '%s' != '%s'. Arrays: '%s' and '%s'", i, get(actual, i), get(expected, i), printObjectAsArray(actual), printObjectAsArray(expected)); return FOUND; }, failMessage, false); } public void isSortedByAsc(int[] array, String failMessage) { if (array == null || array.length == 0) { assertException("isSortedByAsc failed because array have no elements or null"); return; } assertAction("Check tat array sorted by ascending", () -> { for (int i = 1; i < array.length; i++) if (array[i] < array[i - 1]) return format("Array not sorted by ascending. a[%s] > a[%s]", i - 1, i); return FOUND; }, failMessage, false); } public void isSortedByDesc(int[] array, String failMessage) { if (array == null || array.length == 0) { assertException("isSortedByAsc failed because array have no elements or null"); return; } assertAction("Check tat array sorted by ascending", () -> { for (int i = 1; i < array.length; i++) if (array[i] > array[i - 1]) return format("Array not sorted by ascending. a[%s] < a[%s]", i - 1, i); return FOUND; }, failMessage, false); } // ListProcessor public <T> ListChecker eachElementOf(Collection<T> list) { return new ListChecker<>(list); } public <T> ListChecker eachElementOf(T[] array) { return new ListChecker<>(asList(array)); } // Asserts Wait public <T> void areEquals(Supplier<T> actual, T expected, String failMessage) { BooleanSupplier resultAction = (ignoreCase && expected.getClass() == String.class) ? () -> actual.get().equals(expected) : () -> ((String) actual.get()).equalsIgnoreCase((String) expected); waitAction(format("Check that '%s' equals to '%s'", "result", expected), resultAction, failMessage); } /* public <T> ListWaitChecker eachElementOf(Supplier<Collection<T>> list) { return new ListWaitChecker<>(list); } public <T> ListWaitChecker eachElementOfArray(Supplier<T[]> array) { Supplier<Collection<T>> list = () -> asList(array.invoke()); return new ListWaitChecker<>(list); } public class ListWaitChecker<T> { Supplier<Collection<T>> list; private ListWaitChecker(Supplier<Collection<T>> list) { this.list = list; } private void beforeListCheck(String defaultMessage, String expected, String failMessage) { assertAction(format(defaultMessage, print(select(list, Object::toString)), expected), () -> list != null && list.size() > 0 ? FOUND : "list check failed because list is null or empty", failMessage); isListCheck = true; } public void areEquals(Object expected, String failMessage) { beforeListCheck("Check that each item of list '%s' equals to '%s'", expected.toString(), failMessage); for (Object el : list) BaseChecker.this.areEquals(el, expected, failMessage); } public void areEquals(Object expected) { areEquals(expected, null); } public void matches(String regEx, String failMessage) { beforeListCheck("Check that each item of list '%s' matches to regEx '%s'", regEx, failMessage); for (Object el : list) BaseChecker.this.matches((String) el, regEx, failMessage); } public void matches(String regEx) { matches(regEx, null); } public void contains(String expected, String failMessage) { beforeListCheck("Check that each item of list '%s' contains '%s'", expected, failMessage); for (Object el : list) BaseChecker.this.contains((String)el, expected, failMessage); } public void contains(String expected) { contains(expected, null); } public void areSame(Object expected, String failMessage) { beforeListCheck("Check that all items of list '%s' are same with '%s'", expected.toString(), failMessage); for (Object el : list) BaseChecker.this.areSame(el, expected, failMessage); } public void areSame(Object actual, Object expected) { areSame(expected, null); } public void areDifferent(Object expected, String failMessage) { beforeListCheck("Check that all items of list '%s' are different with '%s'", expected.toString(), failMessage); for (Object el : list) BaseChecker.this.areDifferent(el, expected, failMessage); } public void areDifferent(Object actual, Object expected) { areDifferent(expected, null); } }*/ public <T> void areEquals(Supplier<T> actual, T expected) { areEquals(actual, expected, null); } public void matches(Supplier<String> actual, String regEx, String failMessage) { BooleanSupplier resultAction = (ignoreCase && regEx.getClass() == String.class) ? () -> actual.get().matches(regEx) : () -> actual.get().toLowerCase().matches(regEx.toLowerCase()); waitAction(format("Check that '%s' matches to regEx '%s", "result", regEx), resultAction, failMessage); } public void matches(Supplier<String> actual, String regEx) { matches(actual, regEx, null); } public void contains(Supplier<String> actual, String expected, String failMessage) { BooleanSupplier resultAction = (ignoreCase && expected.getClass() == String.class) ? () -> actual.get().contains(expected) : () -> actual.get().toLowerCase().contains(expected.toLowerCase()); waitAction(format("Check that '%s' contains '%s'", "result", expected), resultAction, failMessage); } public void contains(Supplier<String> actual, String expected) { contains(actual, expected, null); } public void isTrue(BooleanSupplier condition, String failMessage) { waitAction(format("Check that condition '%s' is True", "result"), condition, failMessage); } public void isTrue(BooleanSupplier condition) { isTrue(condition, null); } public void isFalse(BooleanSupplier condition, String failMessage) { waitAction(format("Check that condition '%s' is False", "result"), () -> !condition.getAsBoolean(), failMessage); } public void isFalse(BooleanSupplier condition) { isFalse(condition, null); } public void isEmpty(Supplier<Object> obj, String failMessage) { waitAction("Check that Object is empty", () -> isObjEmpty(obj), failMessage); } public void isEmpty(Supplier<Object> obj) { isEmpty(obj, null); } public void isNotEmpty(Supplier<Object> obj, String failMessage) { waitAction("Check that Object is NOT empty", () -> !isObjEmpty(obj), failMessage); } public void isNotEmpty(Supplier<Object> obj) { isNotEmpty(obj, null); } public <T> void areSame(Supplier<T> actual, T expected, String failMessage) { waitAction("Check that Objects are the same", () -> actual == expected, failMessage); } public <T> void areSame(Supplier<T> actual, T expected) { areSame(actual, expected, null); } public <T> void areDifferent(Supplier<T> actual, T expected, String failMessage) { waitAction("Check that Objects are different", () -> actual != expected, failMessage); } public <T> void areDifferent(Supplier<T> actual, T expected) { areDifferent(actual, expected, null); } public <T> void listEquals(Supplier<Collection<T>> actual, Collection<T> expected, String failMessage) { assertAction("Check that Collections are equal", () -> actual.get() != null && expected != null && actual.get().size() == expected.size() ? FOUND : "listEquals failed because one of the Collections is null or empty", failMessage, true); assertAction(null, () -> { T notEqualElement = first(actual.get(), el -> !expected.contains(el)); return (notEqualElement != null) ? String.format("Collections '%s' and '%s' not equals at element '%s'", print(select(actual.get(), Object::toString)), print(LinqUtils.select(expected, Object::toString)), notEqualElement) : FOUND; }, failMessage, true); } public <T> void listEquals(Supplier<Collection<T>> actual, Collection<T> expected) { listEquals(actual, expected, null); } private <T> void entityIncludeMap(Supplier<Map<String, String>> actual, T entity, String failMessage, boolean shouldEqual) { entityIncludeMapArray(() -> MapArray.toMapArray(actual.get()), entity, failMessage, shouldEqual); } private <T> void entityIncludeMapArray(Supplier<MapArray<String, String>> actual, T entity, String failMessage, boolean shouldEqual) { MapArray<String, String> expected = objToSetValue(entity).where((k, value) -> value != null); assertAction("Check that Collections are equal", () -> { MapArray<String, String> actualMap = actual.get(); return actualMap != null && expected != null && (!shouldEqual || actualMap.size() == expected.size()) ? FOUND : "listEquals failed because one of the Collections is null or empty"; }, failMessage, false); assertAction(null, () -> { MapArray<String, String> actualMap = actual.get(); String notEqualElement = expected.first((name, value) -> !actualMap.get(name).equals(value)); return (notEqualElement != null) ? String.format("Collections '%s' and '%s' not equals at element '%s'", print(select(actualMap, Object::toString)), print(select(expected, Object::toString)), notEqualElement) : FOUND; }, failMessage, false); } public <T> void entityIncludeMapArray(Supplier<MapArray<String, String>> actual, T entity, String failMessage) { entityIncludeMapArray(actual, entity, failMessage, false); } public <T> void entityEqualsToMapArray(Supplier<MapArray<String, String>> actual, T entity, String failMessage) { entityIncludeMapArray(actual, entity, failMessage, true); } public <T> void entityIncludeMap(Supplier<Map<String, String>> actual, T entity, String failMessage) { entityIncludeMap(actual, entity, failMessage, false); } public <T> void entityEqualsToMap(Supplier<Map<String, String>> actual, T entity, String failMessage) { entityIncludeMap(actual, entity, failMessage, true); } public <T> void arrayEquals(Supplier<T> actual, T expected, String failMessage) { assertAction("Check that Collections are equal", () -> actual.get() != null && expected != null && actual.get().getClass().isArray() && expected.getClass().isArray() && getLength(actual.get()) == getLength(expected) ? FOUND : "arrayEquals failed because one of the Objects is not Array or empty", failMessage, true); assertAction(null, () -> { for (int i = 0; i <= getLength(actual.get()); i++) if (!get(actual.get(), i).equals(get(expected, i))) return String.format("Arrays not equals at index '%s'. '%s' != '%s'. Arrays: '%s' and '%s'", i, get(actual.get(), i), get(expected, i), printObjectAsArray(actual), printObjectAsArray(expected)); return FOUND; }, failMessage, true); } public <T> void arrayEquals(Supplier<T> actual, T expected) { arrayEquals(actual, expected, null); } public class ListChecker<T> { Collection<T> list; private ListChecker(Collection<T> list) { this.list = list; } private void beforeListCheck(String defaultMessage, String expected, String failMessage) { assertAction(String.format(defaultMessage, print(LinqUtils.select(list, Object::toString)), expected), () -> list != null && !list.isEmpty() ? FOUND : "list check failed because list is null or empty", failMessage, false); isListCheck = true; } public void areEquals(Object expected, String failMessage) { beforeListCheck("Check that each item of list '%s' equals to '%s'", expected.toString(), failMessage); for (Object el : list) BaseMatcher.this.areEquals(el, expected, failMessage); } public void areEquals(Object expected) { areEquals(expected, null); } public void matches(String regEx, String failMessage) { beforeListCheck("Check that each item of list '%s' matches to regEx '%s'", regEx, failMessage); for (Object el : list) BaseMatcher.this.matches((String) el, regEx, failMessage); } public void matches(String regEx) { matches(regEx, null); } public void contains(String expected, String failMessage) { beforeListCheck("Check that each item of list '%s' contains '%s'", expected, failMessage); for (Object el : list) BaseMatcher.this.contains((String) el, expected, failMessage); } public void contains(String expected) { contains(expected, null); } public void areSame(Object expected, String failMessage) { beforeListCheck("Check that all items of list '%s' are same with '%s'", expected.toString(), failMessage); for (Object el : list) BaseMatcher.this.areSame(el, expected, failMessage); } public void areSame(Object expected) { areSame(expected, null); } public void areDifferent(Object expected, String failMessage) { beforeListCheck("Check that all items of list '%s' are different with '%s'", expected.toString(), failMessage); for (Object el : list) BaseMatcher.this.areDifferent(el, expected, failMessage); } public void areDifferent(Object expected) { areDifferent(expected, null); } } }