| // $Id: TestUtil.java 17620 2009-10-04 19:19:28Z hardy.ferentschik $ |
| /* |
| * JBoss, Home of Professional Open Source Copyright 2009, Red Hat, Inc. and/or |
| * its affiliates, and individual contributors by the @authors tag. See the |
| * copyright.txt in the distribution for a full listing of individual |
| * contributors. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); you may not |
| * use this file except in compliance with the License. You may obtain a copy of |
| * the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by |
| * applicable law or agreed to in writing, software distributed under the |
| * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS |
| * OF ANY KIND, either express or implied. See the License for the specific |
| * language governing permissions and limitations under the License. |
| */ |
| |
| package org.hibernate.jsr303.tck.util; |
| |
| import com.google.gwt.core.client.GWT; |
| import com.google.gwt.regexp.shared.MatchResult; |
| import com.google.gwt.regexp.shared.RegExp; |
| import static org.testng.Assert.assertEquals; |
| import static org.testng.Assert.assertTrue; |
| import static org.testng.Assert.fail; |
| |
| import java.lang.annotation.Annotation; |
| import java.util.ArrayList; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Set; |
| |
| import javax.validation.Configuration; |
| import javax.validation.ConstraintViolation; |
| import javax.validation.MessageInterpolator; |
| import javax.validation.Path; |
| import javax.validation.Validator; |
| import javax.validation.ValidatorFactory; |
| import javax.validation.Validation; |
| import javax.validation.bootstrap.GenericBootstrap; |
| import javax.validation.metadata.ConstraintDescriptor; |
| import javax.validation.metadata.ElementDescriptor; |
| import javax.validation.metadata.PropertyDescriptor; |
| import javax.validation.spi.ValidationProvider; |
| |
| /** |
| * Modified by Google. |
| * <ul> |
| * <li>Use RegExp instead of Pattern</li> |
| * </ul> |
| * @author Hardy Ferentschik |
| */ |
| public final class TestUtil { |
| |
| private static String VALIDATION_PROVIDER_TEST_CLASS = "validation.provider"; |
| |
| private static ValidationProvider<?> validationProviderUnderTest; |
| |
| private TestUtil() { |
| } |
| |
| public static Validator getValidatorUnderTest() { |
| return getValidatorFactoryUnderTest().getValidator(); |
| } |
| |
| public static ValidationProvider<?> getValidationProviderUnderTest() { |
| if (validationProviderUnderTest == null) { |
| instantiateValidationProviderUnderTest(); |
| } |
| return validationProviderUnderTest; |
| } |
| |
| public static ValidatorFactory getValidatorFactoryUnderTest() { |
| Configuration<?> config = getConfigurationUnderTest(); |
| return config.buildValidatorFactory(); |
| } |
| |
| public static Configuration<?> getConfigurationUnderTest() { |
| if (validationProviderUnderTest == null) { |
| instantiateValidationProviderUnderTest(); |
| } |
| |
| GenericBootstrap bootstrap = Validation.byDefaultProvider(); |
| return bootstrap.configure(); |
| } |
| |
| public static MessageInterpolator getDefaultMessageInterpolator() { |
| Configuration<?> config = getConfigurationUnderTest(); |
| return config.getDefaultMessageInterpolator(); |
| } |
| |
| public static <T> void assertCorrectNumberOfViolations( |
| Set<ConstraintViolation<T>> violations, int expectedViolations) { |
| assertEquals(violations.size(), expectedViolations, |
| "Wrong number of constraint violations. Expected: " |
| + expectedViolations + " Actual: " + violations.size()); |
| } |
| |
| public static <T> void assertCorrectConstraintViolationMessages( |
| Set<ConstraintViolation<T>> violations, String... messages) { |
| List<String> actualMessages = new ArrayList<String>(); |
| for (ConstraintViolation<?> violation : violations) { |
| actualMessages.add(violation.getMessage()); |
| } |
| |
| assertTrue(actualMessages.size() == messages.length, |
| "Wrong number or error messages. Expected: " + messages.length |
| + " Actual: " + actualMessages.size()); |
| |
| for (String expectedMessage : messages) { |
| assertTrue(actualMessages.contains(expectedMessage), "The message '" |
| + expectedMessage |
| + "' should have been in the list of actual messages: " |
| + actualMessages); |
| actualMessages.remove(expectedMessage); |
| } |
| assertTrue(actualMessages.isEmpty(), |
| "Actual messages contained more messages as specified expected messages"); |
| } |
| |
| public static <T> void assertCorrectConstraintTypes( |
| Set<ConstraintViolation<T>> violations, |
| Class<?>... expectedConsraintTypes) { |
| List<String> actualConstraintTypes = new ArrayList<String>(); |
| for (ConstraintViolation<?> violation : violations) { |
| actualConstraintTypes.add(((Annotation) violation.getConstraintDescriptor().getAnnotation()).annotationType().getName()); |
| } |
| |
| assertEquals(expectedConsraintTypes.length, actualConstraintTypes.size(), |
| "Wrong number of constraint types."); |
| |
| for (Class<?> expectedConstraintType : expectedConsraintTypes) { |
| assertTrue( |
| actualConstraintTypes.contains(expectedConstraintType.getName()), |
| "The constraint type " + expectedConstraintType.getName() |
| + " is not in the list of actual violated constraint types: " |
| + actualConstraintTypes); |
| } |
| } |
| |
| public static <T> void assertCorrectPropertyPaths( |
| Set<ConstraintViolation<T>> violations, String... propertyPaths) { |
| List<Path> propertyPathsOfViolations = new ArrayList<Path>(); |
| for (ConstraintViolation<?> violation : violations) { |
| propertyPathsOfViolations.add(violation.getPropertyPath()); |
| } |
| |
| assertEquals(propertyPaths.length, propertyPathsOfViolations.size(), |
| "Wrong number of property paths. Expected: " + propertyPaths.length |
| + " Actual: " + propertyPathsOfViolations.size()); |
| |
| for (String propertyPath : propertyPaths) { |
| Path expectedPath = PathImpl.createPathFromString(propertyPath); |
| boolean containsPath = false; |
| for (Path actualPath : propertyPathsOfViolations) { |
| if (assertEqualPaths(expectedPath, actualPath)) { |
| containsPath = true; |
| break; |
| } |
| } |
| if (!containsPath) { |
| fail(expectedPath |
| + " is not in the list of path instances contained in the actual constraint violations: " |
| + propertyPathsOfViolations); |
| } |
| } |
| } |
| |
| public static <T> void assertConstraintViolation( |
| ConstraintViolation<T> violation, Class<?> rootBean, Object invalidValue, |
| String propertyPath) { |
| Path expectedPath = PathImpl.createPathFromString(propertyPath); |
| if (!assertEqualPaths(violation.getPropertyPath(), expectedPath)) { |
| fail("Property paths differ. Actual: " + violation.getPropertyPath() |
| + " Expected: " + expectedPath); |
| } |
| |
| assertEquals(violation.getRootBeanClass(), rootBean, "Wrong root bean."); |
| assertEquals(violation.getInvalidValue(), invalidValue, |
| "Wrong invalid value."); |
| } |
| |
| public static boolean assertEqualPaths(Path p1, Path p2) { |
| Iterator<Path.Node> p1Iterator = p1.iterator(); |
| Iterator<Path.Node> p2Iterator = p2.iterator(); |
| while (p1Iterator.hasNext()) { |
| Path.Node p1Node = p1Iterator.next(); |
| if (!p2Iterator.hasNext()) { |
| return false; |
| } |
| Path.Node p2Node = p2Iterator.next(); |
| |
| // do the comparison on the node values |
| if (p2Node.getName() == null) { |
| if (p1Node.getName() != null) { |
| return false; |
| } |
| } else if (!p2Node.getName().equals(p1Node.getName())) { |
| return false; |
| } |
| |
| if (p2Node.isInIterable() != p1Node.isInIterable()) { |
| return false; |
| } |
| |
| if (p2Node.getIndex() == null) { |
| if (p1Node.getIndex() != null) { |
| return false; |
| } |
| } else if (!p2Node.getIndex().equals(p1Node.getIndex())) { |
| return false; |
| } |
| |
| if (p2Node.getKey() == null) { |
| if (p1Node.getKey() != null) { |
| return false; |
| } |
| } else if (!p2Node.getKey().equals(p1Node.getKey())) { |
| return false; |
| } |
| } |
| |
| return !p2Iterator.hasNext(); |
| } |
| |
| public static PropertyDescriptor getPropertyDescriptor(Class<?> clazz, |
| String property) { |
| Validator validator = getValidatorUnderTest(); |
| return validator.getConstraintsForClass(clazz).getConstraintsForProperty( |
| property); |
| } |
| |
| public static Set<ConstraintDescriptor<?>> getConstraintDescriptorsFor( |
| Class<?> clazz, String property) { |
| ElementDescriptor elementDescriptor = getPropertyDescriptor(clazz, property); |
| return elementDescriptor.getConstraintDescriptors(); |
| } |
| |
| public static Object getInputStreamForPath(String path) { |
| |
| return null; |
| } |
| |
| private static <U extends ValidationProvider<?>> void instantiateValidationProviderUnderTest() { |
| validationProviderUnderTest = GWT.create(ValidationProvider.class); |
| } |
| |
| public static class PathImpl implements Path { |
| |
| /** |
| * Regular expression used to split a string path into its elements. |
| * |
| * @see <a href="http://www.regexplanet.com/simple/index.jsp">Regular |
| * expression tester</a> |
| */ |
| private static final RegExp pathPattern = RegExp.compile("(\\w+)(\\[(\\w*)\\])?(\\.(.*))*"); |
| |
| private static final String PROPERTY_PATH_SEPARATOR = "."; |
| |
| private final List<Node> nodeList; |
| |
| public static PathImpl createPathFromString(String propertyPath) { |
| if (propertyPath == null) { |
| throw new IllegalArgumentException( |
| "null is not allowed as property path."); |
| } |
| |
| if (propertyPath.length() == 0) { |
| return createNewPath(null); |
| } |
| |
| return parseProperty(propertyPath); |
| } |
| |
| public static PathImpl createNewPath(String name) { |
| PathImpl path = new PathImpl(); |
| NodeImpl node = new NodeImpl(name); |
| path.addNode(node); |
| return path; |
| } |
| |
| private PathImpl() { |
| nodeList = new ArrayList<Node>(); |
| } |
| |
| public void addNode(Node node) { |
| nodeList.add(node); |
| } |
| |
| public Iterator<Path.Node> iterator() { |
| return nodeList.iterator(); |
| } |
| |
| @Override |
| public String toString() { |
| StringBuilder builder = new StringBuilder(); |
| Iterator<Path.Node> iter = iterator(); |
| while (iter.hasNext()) { |
| Node node = iter.next(); |
| builder.append(node.toString()); |
| if (iter.hasNext()) { |
| builder.append(PROPERTY_PATH_SEPARATOR); |
| } |
| } |
| return builder.toString(); |
| } |
| |
| private static PathImpl parseProperty(String property) { |
| PathImpl path = new PathImpl(); |
| String tmp = property; |
| do { |
| MatchResult matcher = pathPattern.exec(tmp); |
| if (matcher != null) { |
| String value = matcher.getGroup(1); |
| String indexed = matcher.getGroup(2); |
| String index = matcher.getGroup(3); |
| NodeImpl node = new NodeImpl(value); |
| |
| if (indexed != null && indexed.length() > 0) { |
| node.setInIterable(true); |
| } |
| if (index != null && index.length() > 0) { |
| try { |
| Integer i = Integer.parseInt(index); |
| node.setIndex(i); |
| } catch (NumberFormatException e) { |
| node.setKey(index); |
| } |
| } |
| path.addNode(node); |
| tmp = matcher.getGroup(5); |
| } else { |
| throw new IllegalArgumentException("Unable to parse property path " |
| + property); |
| } |
| } while (tmp != null && tmp.length() > 0); |
| return path; |
| } |
| } |
| |
| public static class NodeImpl implements Path.Node { |
| |
| private static final String INDEX_OPEN = "["; |
| private static final String INDEX_CLOSE = "]"; |
| |
| private final String name; |
| private boolean isInIterable; |
| private Integer index; |
| private Object key; |
| |
| public NodeImpl(String name) { |
| this.name = name; |
| } |
| |
| NodeImpl(Path.Node node) { |
| this.name = node.getName(); |
| this.isInIterable = node.isInIterable(); |
| this.index = node.getIndex(); |
| this.key = node.getKey(); |
| } |
| |
| public String getName() { |
| return name; |
| } |
| |
| public boolean isInIterable() { |
| return isInIterable; |
| } |
| |
| public void setInIterable(boolean inIterable) { |
| isInIterable = inIterable; |
| } |
| |
| public Integer getIndex() { |
| return index; |
| } |
| |
| public void setIndex(Integer index) { |
| isInIterable = true; |
| this.index = index; |
| } |
| |
| public Object getKey() { |
| return key; |
| } |
| |
| public void setKey(Object key) { |
| isInIterable = true; |
| this.key = key; |
| } |
| |
| @Override |
| public String toString() { |
| StringBuilder builder = new StringBuilder(name == null ? "" : name); |
| if (isInIterable) { |
| builder.append(INDEX_OPEN); |
| if (getIndex() != null) { |
| builder.append(getIndex()); |
| } else if (getKey() != null) { |
| builder.append(getKey()); |
| } |
| builder.append(INDEX_CLOSE); |
| } |
| return builder.toString(); |
| } |
| } |
| } |