/*
* JBoss, Home of Professional Open Source
* Copyright 2010-2016, Red Hat, Inc. and individual contributors
* by the @authors tag. See the copyright.txt in the distribution for a
* full listing of individual contributors.
*
* This 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 software 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.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.richfaces.tests.metamer.ftest.extension.configurator.templates;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.EnumSet;
import java.util.List;
import org.richfaces.tests.metamer.Template;
import org.richfaces.tests.metamer.TemplatesList;
import org.richfaces.tests.metamer.ftest.extension.configurator.ConfiguratorExtension;
import org.richfaces.tests.metamer.ftest.extension.configurator.config.Config;
import org.richfaces.tests.metamer.ftest.extension.configurator.config.FieldConfig;
import org.richfaces.tests.metamer.ftest.extension.configurator.skip.annotation.Skip;
import org.richfaces.tests.metamer.ftest.extension.configurator.templates.annotation.Templates;
import org.richfaces.tests.utils.ReflectionUtils;
import com.google.common.collect.Lists;
/**
* The templates lists are separated with ',', more templates in a template list are connected with '+'.
* <code>mvn verify -Dtemplates=*,accordion,accordion+tabPanel</code>
* Will run all (possible) tests in: 1) all templates, 2) accordion, 3) tabPanel inside accordion (all tests that can run in both of them).
*
* @author <a href="mailto:jstefek@redhat.com">Jiri Stefek</a>
*/
public class TemplatesConfigurator implements ConfiguratorExtension {
public static final String[] ALL_TEMPLATES_STRINGS = { "all", "*" };
private static final String PLAIN = "plain";
private static final TemplatesList PLAIN_TEMPLATE = TemplatesList.parseFrom(PLAIN);
private static final String TEMPLATE_LIST_SEPARATOR = ",";
private static final String TEMPLATE_PROPERTY_NAME = "templates";
private static String getTemplatePropertyValue() {
return System.getProperty(TEMPLATE_PROPERTY_NAME, PLAIN);
}
private List<TemplatesList> addTemplatesListForEachTestedTemplate(EnumSet<Template> defaultTestedTemplates) {
List<TemplatesList> result = Lists.newLinkedList();
for (Template template : defaultTestedTemplates) {
result.add(removeRedundantPlainTemplate(TemplatesList.fromTemplate(template)));
}
return result;
}
private void checkIfAnnotationIsValid(Templates annotation) throws IllegalStateException {
boolean exludedIsEmpty = true, valuesIsEmpty = true;
String[] values;
if (annotation.exclude() != null) {
values = annotation.exclude();
for (String string : values) {
if (!string.isEmpty()) {
exludedIsEmpty = false;
}
}
}
if (annotation.value() != null) {
values = annotation.value();
for (String string : values) {
if (!string.isEmpty()) {
valuesIsEmpty = false;
}
}
}
if ((!valuesIsEmpty && !exludedIsEmpty) || (valuesIsEmpty && exludedIsEmpty)) {
throw new IllegalArgumentException("More annotation fields are set or both fields are empty. Consider using only 'values' or 'excluded'");
}
}
@Override
public List<Config> createConfigurations(Method m, Object testInstance) {
List<Config> result = Lists.newLinkedList();
Templates annotationOnMethod = m.getAnnotation(Templates.class);
Templates annotationOnTestClass = testInstance.getClass().getAnnotation(Templates.class);
Templates annotation = (annotationOnMethod != null ? annotationOnMethod : annotationOnTestClass);
Field templateField = ReflectionUtils.getFirstFieldAnnotatedWith(Templates.class, testInstance);
// if Skip annotation is present, no @Templates is specified and template property (-Dtemplates) is set to all
// templates, then run test only in plain template
Skip skipAnnotation = m.getAnnotation(Skip.class);
if (annotation == null && skipAnnotation != null && isAllTemplateString(getTemplatePropertyValue())) {
result.add(new FieldConfig(testInstance, PLAIN_TEMPLATE, templateField));
return result;
}
EnumSet<Template> defaultTestedTemplates = getTestedTemplatesFromField(templateField);
EnumSet<Template> possibleTemplates = getAllPossibleTemplatesFromAnnotation(annotation, defaultTestedTemplates);
if (possibleTemplates.isEmpty()) {
throw new IllegalStateException("No possible templates configured!");
}
for (TemplatesList templatesList : getRunnableTemplatesLists(parseTemplatesListFromSystemProperty(defaultTestedTemplates), possibleTemplates)) {
result.add(new FieldConfig(testInstance, templatesList, templateField));
}
return result;
}
private EnumSet<Template> getAllPossibleTemplatesFromAnnotation(Templates annotationOnMethodOrOnClass, EnumSet<Template> defaultTestedTemplates) {
if (annotationOnMethodOrOnClass == null) {// annotation is null >>> ALL templates are possible
return defaultTestedTemplates.clone();
}
checkIfAnnotationIsValid(annotationOnMethodOrOnClass);
EnumSet<Template> set = null;
if (annotationOnMethodOrOnClass.value() != null && !Arrays.asList(annotationOnMethodOrOnClass.value()).isEmpty()) {
set = EnumSet.copyOf(parseTemplates(annotationOnMethodOrOnClass.value()));
} else if (annotationOnMethodOrOnClass.exclude() != null && !Arrays.asList(annotationOnMethodOrOnClass.exclude()).isEmpty()) {
set = defaultTestedTemplates.clone();
set.removeAll(parseTemplates(annotationOnMethodOrOnClass.exclude()));
} else {
throw new IllegalStateException("All of the annotation values are null!");
}
return set;
}
private List<TemplatesList> getRunnableTemplatesLists(List<TemplatesList> listOfTemplates, EnumSet<Template> possibleTemplates) {
List<TemplatesList> willRunInTemplatesLists = Lists.newLinkedList();
for (TemplatesList templatesList : listOfTemplates) {
if (isTemplatesListValid(templatesList, possibleTemplates)) {
willRunInTemplatesLists.add(templatesList);
} else {
// System.out.println("IGNORED templates list: " + templatesList);
}
}
return willRunInTemplatesLists;
}
private EnumSet<Template> getTestedTemplatesFromField(Field fielWithTemplatesAnnotation) {
EnumSet<Template> result = EnumSet.noneOf(Template.class);
String[] value = fielWithTemplatesAnnotation.getAnnotation(Templates.class).value();
for (String string : value) {
result.add(Template.valueFrom(string));
}
return result;
}
@Override
public boolean ignoreConfigurations() {
return Boolean.FALSE;
}
private boolean isAllTemplateString(String templatesListString) throws IllegalArgumentException {
for (String allTemplateString : ALL_TEMPLATES_STRINGS) {
if (templatesListString.contains(allTemplateString)) {
if (templatesListString.equalsIgnoreCase(allTemplateString)) {
return true;
} else {
throw new IllegalArgumentException("Cannot have a special ALL templates string in a TemplatesList containing more templates");
}
}
}
return false;
}
private boolean isTemplatesListValid(TemplatesList templatesList, EnumSet<Template> possibleTemplates) {
for (Template template : templatesList) {
if (!possibleTemplates.contains(template)) {
return false;
}
}
return true;
}
private List<Template> parseTemplates(String[] templates) {
List<Template> result = Lists.newLinkedList();
for (String template : templates) {
result.add(Template.valueFrom(template));
}
return result;
}
private List<TemplatesList> parseTemplatesListFromSystemProperty(EnumSet<Template> defaultTestedTemplates) {
List<TemplatesList> result = Lists.newLinkedList();
String[] split = getTemplatePropertyValue().split(TEMPLATE_LIST_SEPARATOR);
for (String templatesListString : split) {
if (isAllTemplateString(templatesListString)) {
result.addAll(addTemplatesListForEachTestedTemplate(defaultTestedTemplates));
} else {
result.add(removeRedundantPlainTemplate(TemplatesList.parseFrom(templatesListString)));
}
}
if (result.isEmpty()) {
throw new IllegalStateException("No templates to run in were specified.");
}
return result;
}
private TemplatesList removeRedundantPlainTemplate(TemplatesList tList) {
if (tList.size() > 1 && tList.get(tList.size() - 1).equals(Template.PLAIN)) {
// the TemplateList implementation inserts PLAIN template as the last record => delete it
tList.remove(tList.size() - 1);
}
return tList;
}
@Override
public boolean skipTestIfNoConfiguration() {
return Boolean.TRUE;
}
}