org.nuiton.validator.ValidatorTestHelper Maven / Gradle / Ivy
package org.nuiton.validator;
/*
* #%L
* Validation :: Test
* %%
* Copyright (C) 2021 - 2024 Ultreia.io
* %%
* 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 (at your option) 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.
*
* You should have received a copy of the GNU General Public
* License along with this program. If not, see
* .
* #L%
*/
import org.apache.commons.lang3.SystemUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.junit.Assert;
import org.nuiton.validator.xwork2.XWork2NuitonValidator;
import java.io.File;
import java.io.FilenameFilter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Helper methods to test the validator api.
*
* @author Tony Chemit - [email protected]
* @since 2.0
*/
public class ValidatorTestHelper {
private static final Logger log = LogManager.getLogger(ValidatorTestHelper.class);
public static File getBasedir() {
// Search basedir from maven environment
String basedirPath = System.getenv("basedir");
if (basedirPath == null) {
// hope the tests are running from the root of the module :)
basedirPath = new File("").getAbsolutePath();
}
return new File(basedirPath);
}
public static void assertValidatorModel(NuitonValidator> validator,
String expectedContext,
Class> expectedType,
NuitonValidatorScope... expectedScopes) {
Assert.assertNotNull(validator);
NuitonValidatorModel> model = validator.getModel();
Assert.assertNotNull(model);
Assert.assertEquals(expectedContext, model.getContext());
Assert.assertEquals(expectedType, model.getType());
Set scopes = model.getScopes();
for (NuitonValidatorScope expectedScope : expectedScopes) {
Assert.assertTrue(scopes.contains(expectedScope));
}
}
public static void assertValidatorEffectiveScopes(NuitonValidator> validator,
NuitonValidatorScope... expectedScopes) {
Assert.assertNotNull(validator);
Set effectiveScopes = validator.getEffectiveScopes();
Assert.assertEquals(expectedScopes.length, effectiveScopes.size());
for (NuitonValidatorScope expectedScope : expectedScopes) {
Assert.assertTrue(effectiveScopes.contains(expectedScope));
}
}
public static void assertValidatorEffectiveFields(NuitonValidator> validator,
String... expectedFields) {
Assert.assertNotNull(validator);
Set effectiveFields = validator.getEffectiveFields();
Assert.assertEquals(expectedFields.length, effectiveFields.size());
for (String expectedField : expectedFields) {
Assert.assertTrue(effectiveFields.contains(expectedField));
}
}
public static void assertValidatorEffectiveFields(NuitonValidator> validator,
NuitonValidatorScope scope,
String... expectedFields) {
Assert.assertNotNull(validator);
Set effectiveFields = validator.getEffectiveFields(scope);
Assert.assertEquals(expectedFields.length, effectiveFields.size());
for (String expectedField : expectedFields) {
Assert.assertTrue(effectiveFields.contains(expectedField));
}
}
public static void assertFieldMessages(NuitonValidatorResult result,
NuitonValidatorScope scope,
String field,
String... expectedMessages) {
if (expectedMessages.length == 0) {
// no messages
boolean hasMessages = result.hasMessagesForScope(field, scope);
Assert.assertFalse(hasMessages);
} else {
// with messages
boolean hasMessages = result.hasMessagesForScope(field, scope);
Assert.assertTrue(hasMessages);
List messages = result.getMessagesForScope(field, scope);
Assert.assertNotNull(messages);
Assert.assertEquals(expectedMessages.length, messages.size());
for (String expectedMessage : expectedMessages) {
Assert.assertTrue(messages.contains(expectedMessage));
}
}
}
public static SortedSet> detectValidators(File rootDirectory, NuitonValidatorProvider provider, Pattern contextFilter, NuitonValidatorScope[] scopes, Class>... types) {
if (scopes == null) {
// use all scopes
scopes = NuitonValidatorScope.values();
}
SortedSet> result =
new TreeSet<>(new ValidatorComparator());
for (Class> c : types) {
File dir = getClassDir(rootDirectory, c);
if (!dir.exists()) {
// pas de repertoire adequate
if (log.isDebugEnabled()) {
log.debug("skip none existing directory " + dir);
}
continue;
}
String[] contexts = getContexts(c, dir);
if (log.isDebugEnabled()) {
log.debug("contexts : " + Arrays.toString(contexts));
}
if (contexts.length > 0) {
String[] realContexts = getContextsWithoutScopes(contexts);
if (log.isDebugEnabled()) {
log.debug("realContexts : " +
Arrays.toString(realContexts));
}
if (contextFilter != null) {
// filter contexts
realContexts = getFilterContexts(contextFilter, realContexts);
if (log.isDebugEnabled()) {
log.debug("filterContexts : " + Arrays.toString(realContexts));
}
}
for (String context : realContexts) {
NuitonValidator> validator = getValidator(provider, c, context.isEmpty() ? null : context, scopes);
if (validator != null) {
result.add(validator);
}
}
}
}
return result;
}
/**
* Pour un context et un type d'entité donné, instancie un validateur et
* test si ce validateur est utilisable (i.e qu'il admet des champs à
* valider).
*
* Si aucun champ n'est trouvé dans le validateur, alors on retourne null.
*
* @param le type du bean
* @param provider provider to get validators
* @param klass le type du bean
* @param context le context du validateur
* @param scopes les scopes a utiliser (si {@code null} alors pas de
* filtre sur les scopes)
* @return le validateur initialisé, ou null si aucun scope
* détecté dans le validateur.
*/
protected static NuitonValidator getValidator(NuitonValidatorProvider provider,
Class klass,
String context,
NuitonValidatorScope... scopes) {
NuitonValidatorModel model = provider.newModel(klass, context, scopes);
NuitonValidator valitator = provider.newValidator(model);
Set realScopes = valitator.getEffectiveScopes();
if (realScopes.isEmpty()) {
valitator = null;
if (log.isDebugEnabled()) {
log.debug(klass + " : validator skip (no scopes detected)");
}
} else {
if (log.isDebugEnabled()) {
log.debug(klass + " : keep validator " + valitator);
}
}
return valitator;
}
/**
* @return the file separator escaped for a regex regarding the os used.
*/
public static String getFileSeparatorRegex() {
String result;
if (SystemUtils.IS_OS_WINDOWS) {
result = "\\\\";
} else {
result = "/";
}
return result;
}
protected static File getClassDir(File sourceRoot, Class> clazz) {
String path = clazz.getPackage().getName();
path = path.replaceAll("\\.", getFileSeparatorRegex());
return new File(sourceRoot, path);
}
protected static String[] getContexts(Class> clazz, File dir) {
Set result = new TreeSet<>();
ValidatorFilenameFilter filter = new ValidatorFilenameFilter(clazz);
if (log.isDebugEnabled()) {
log.debug("dir : " + dir);
}
String[] files = dir.list(filter);
for (String file : Objects.requireNonNull(files)) {
if (log.isDebugEnabled()) {
log.debug("file " + file);
}
String context = file.substring(
filter.prefix.length(),
file.length() - ValidatorFilenameFilter.SUFFIX.length()
);
if (log.isDebugEnabled()) {
log.debug("detect " + clazz.getSimpleName() +
" context [" + context + "]");
}
result.add(context);
}
return result.toArray(new String[0]);
}
protected static String[] getContextsWithoutScopes(String[] contexts) {
Set result = new TreeSet<>();
NuitonValidatorScope[] scopes = NuitonValidatorScope.values();
for (String context : contexts) {
for (NuitonValidatorScope scope : scopes) {
String scopeName = scope.name().toLowerCase();
if (!context.endsWith(scopeName)) {
continue;
}
if (log.isDebugEnabled()) {
log.debug("detect context : " + context);
}
String realContext = context.substring(0, context.length() - scopeName.length()
);
if (realContext.endsWith("-")) {
realContext = realContext.substring(0, realContext.length() - 1);
}
result.add(realContext);
}
}
return result.toArray(new String[0]);
}
protected static String[] getFilterContexts(Pattern contextFilter, String[] realContexts) {
List result = new ArrayList<>();
for (String c : realContexts) {
Matcher m = contextFilter.matcher(c);
if (m.matches()) {
result.add(c);
}
}
return result.toArray(new String[0]);
}
protected static class ValidatorFilenameFilter implements FilenameFilter {
protected static final String SUFFIX = "-validation.xml";
protected Class> clazz;
protected String prefix;
public ValidatorFilenameFilter(Class> clazz) {
this.clazz = clazz;
prefix = clazz.getSimpleName() + "-";
}
@Override
public boolean accept(File dir, String name) {
boolean result = name.endsWith(SUFFIX);
if (result) {
result = name.startsWith(prefix);
}
return result;
}
}
protected static class ValidatorComparator implements Comparator> {
@Override
public int compare(NuitonValidator> o1, NuitonValidator> o2) {
NuitonValidatorModel> model1 = ((XWork2NuitonValidator>) o1).getModel();
NuitonValidatorModel> model2 = ((XWork2NuitonValidator>) o2).getModel();
String contextName1 = model1.getType().getName() + "-" + (model1.getContext() == null ? "" : model1.getContext());
String contextName2 = model2.getType().getName() + "-" + (model2.getContext() == null ? "" : model2.getContext());
return contextName1.compareTo(contextName2);
}
}
}