diff --git a/pom.xml b/pom.xml
index ba25028..10eb0fa 100644
--- a/pom.xml
+++ b/pom.xml
@@ -107,6 +107,14 @@
+
+
+ org.jsoup
+ jsoup
+ 1.8.2
+ test
+
+
org.spockframework
spock-core
diff --git a/src/test/groovy/cz/jirutka/validator/collection/CommonEachValidatorIT.groovy b/src/test/groovy/cz/jirutka/validator/collection/CommonEachValidatorIT.groovy
index 4f9e6b7..3c49925 100644
--- a/src/test/groovy/cz/jirutka/validator/collection/CommonEachValidatorIT.groovy
+++ b/src/test/groovy/cz/jirutka/validator/collection/CommonEachValidatorIT.groovy
@@ -1,7 +1,7 @@
/*
* The MIT License
*
- * Copyright 2013-2014 Jakub Jirutka .
+ * Copyright 2013-2015 Jakub Jirutka .
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -29,17 +29,14 @@ import spock.lang.Issue
import spock.lang.Specification
import spock.lang.Unroll
-import javax.validation.Validation
-
import static cz.jirutka.validator.collection.TestUtils.evalClassWithConstraint
+import static cz.jirutka.validator.collection.TestUtils.validate
@Unroll
class CommonEachValidatorIT extends Specification {
static HV_VERSION = HibernateValidatorInfo.getVersion()
- def validator = Validation.buildDefaultValidatorFactory().getValidator()
-
def constraint = null
@@ -141,10 +138,6 @@ class CommonEachValidatorIT extends Specification {
//////// Helpers ////////
- def validate(entity) {
- validator.validate(entity)
- }
-
void assertViolations(Object value, boolean shouldBeValid, Integer invalidIndex, String expectedMessage) {
def entity = evalClassWithConstraint(constraint, value)
def propertyPath = HV_VERSION >= 5_0_0 ? "valuesList[${invalidIndex}]" : 'valuesList'
diff --git a/src/test/groovy/cz/jirutka/validator/collection/TestUtils.groovy b/src/test/groovy/cz/jirutka/validator/collection/TestUtils.groovy
index 9695eb8..331652f 100644
--- a/src/test/groovy/cz/jirutka/validator/collection/TestUtils.groovy
+++ b/src/test/groovy/cz/jirutka/validator/collection/TestUtils.groovy
@@ -1,7 +1,7 @@
/*
* The MIT License
*
- * Copyright 2013-2014 Jakub Jirutka .
+ * Copyright 2013-2015 Jakub Jirutka .
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -26,6 +26,8 @@ package cz.jirutka.validator.collection
import org.hibernate.validator.internal.util.annotationfactory.AnnotationDescriptor
import org.hibernate.validator.internal.util.annotationfactory.AnnotationFactory
+import javax.validation.Validation
+
class TestUtils {
static evalClassWithConstraint(annotationLine, List values) {
@@ -44,12 +46,20 @@ class TestUtils {
new GroovyClassLoader().parseClass(template).newInstance()
}
+ static evalClassWithConstraint(Class annotationType, Map attributes, List values) {
+ evalClassWithConstraint(createAnnotationString(annotationType, attributes), values)
+ }
+
static toLiteral(value) {
switch (value) {
case null : return null
- case Number : // go to next
- case Boolean : return String.valueOf(value)
- default : return "'${value.toString()}'"
+ case String : return "'${value.toString()}'"
+ case Long : return "${value}L"
+ case List : return '[' + value.collect { toLiteral(it) }.join(', ') + ']'
+ case Map : return '[' + value.collect { k, v -> "${k}: ${ toLiteral(v) }" }.join(',') + ']'
+ case Enum : return "${value.declaringClass.name}.${value.name()}"
+ case Date : return "new Date(${toLiteral(value.time)})"
+ default : return String.valueOf(value)
}
}
@@ -61,4 +71,13 @@ class TestUtils {
def desc = AnnotationDescriptor.getInstance(annotationType, attributes)
AnnotationFactory.create(desc)
}
+
+ static createAnnotationString(Class annotationType, Map attributes) {
+ def attrsLine = attributes.collect { k, v -> "${k}=${toLiteral(v)}" }.join(', ')
+ "@${annotationType.name}(${attrsLine})"
+ }
+
+ static validate(entity) {
+ Validation.buildDefaultValidatorFactory().validator.validate(entity)
+ }
}
diff --git a/src/test/groovy/cz/jirutka/validator/collection/constraints/EachAnnotationTest.groovy b/src/test/groovy/cz/jirutka/validator/collection/constraints/EachAnnotationTest.groovy
index 2b4019f..2f7fd5d 100644
--- a/src/test/groovy/cz/jirutka/validator/collection/constraints/EachAnnotationTest.groovy
+++ b/src/test/groovy/cz/jirutka/validator/collection/constraints/EachAnnotationTest.groovy
@@ -1,7 +1,7 @@
/*
* The MIT License
*
- * Copyright 2013-2014 Jakub Jirutka .
+ * Copyright 2013-2015 Jakub Jirutka .
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -23,23 +23,38 @@
*/
package cz.jirutka.validator.collection.constraints
+import cz.jirutka.validator.collection.internal.HibernateValidatorInfo
+import org.hibernate.validator.constraints.EAN.Type
import spock.lang.Specification
import spock.lang.Unroll
+import static cz.jirutka.validator.collection.TestUtils.evalClassWithConstraint
+import static cz.jirutka.validator.collection.TestUtils.validate
+
@Unroll
class EachAnnotationTest extends Specification {
- static final CONSTRAINTS = [
- // JSR 303/349
+ static final HV_VERSION = HibernateValidatorInfo.getVersion()
+
+ // List of @Each* annotations for constraints defined in JSR 303/349.
+ static final CONSTRAINTS_JSR = [
EachAssertFalse, EachAssertTrue, EachDecimalMax, EachDecimalMin,
EachDigits, EachFuture, EachMax, EachMin, EachNotNull, EachPast,
- EachPattern, EachSize,
- // Hibernate
- EachCreditCardNumber, EachEAN, EachEmail, EachLength, EachLuhnCheck,
- EachMod10Check, EachMod11Check, EachNotBlank, EachNotEmpty,
- EachRange, EachSafeHtml, EachScriptAssert, EachURL
+ EachPattern, EachSize
+ ]
+
+ // List of @Each* annotations for Hibernate constraints in HV 4.3.0.
+ static final CONSTRAINTS_HV = [
+ EachCreditCardNumber, EachEmail, EachLength, EachNotBlank,
+ EachNotEmpty, EachRange, EachScriptAssert, EachURL
+ ]
+
+ // List of @Each* annotations for Hibernate constraints in HV 5.1.0 and newer.
+ static final CONSTRAINTS_5_1_0 = [
+ EachEAN, EachLuhnCheck, EachMod10Check, EachMod11Check, EachSafeHtml
]
+
def 'verify that @#name is annotated with @EachConstraint(validateAs = #expValidateAsName)'() {
expect:
constraint.isAnnotationPresent(EachConstraint)
@@ -47,7 +62,7 @@ class EachAnnotationTest extends Specification {
def validateAs = constraint.getAnnotation(EachConstraint).validateAs()
constraint.simpleName == /Each${validateAs.simpleName}/
where:
- constraint << CONSTRAINTS
+ constraint << eachConstraints
name = constraint.simpleName
expValidateAsName = name.replaceFirst('^Each', '') + '.class'
}
@@ -58,13 +73,72 @@ class EachAnnotationTest extends Specification {
expect:
attributesTypesSet(constraint).containsAll attributesTypesSet(validateAs)
where:
- constraint << CONSTRAINTS
+ constraint << eachConstraints
+ }
+
+ def 'verify that @#constraint.simpleName basically works'() {
+ setup:
+ // skip test for constraints that doesn't work in the current HV version
+ if (!eachConstraints.contains(constraint)) return
+ and:
+ def validEntity = evalClassWithConstraint(constraint, attributes, validValue)
+ def invalidEntity = evalClassWithConstraint(constraint, attributes, invalidValue)
+ expect:
+ validate(validEntity).empty
+ ! validate(invalidEntity).empty
+ where:
+ constraint | attributes | validValue | invalidValue
+ EachAssertFalse | [:] | [false, false] | [false, true]
+ EachAssertTrue | [:] | [true, true] | [true, false]
+ //EachCreditCardNumber | [:] | [4417123456789113] | [4417123456789112] FIXME!
+ EachDecimalMax | [value: '3'] | [1, 2, 3] | [2, 3, 4]
+ EachDecimalMax | [value: '3'] | ['1', '2', '3'] | ['2', '3', '4']
+ EachDecimalMin | [value: '3'] | [3, 4, 5] | [2, 3, 4]
+ EachDecimalMin | [value: '3'] | ['3', '4', '5'] | ['2', '3', '4']
+ EachDigits | [integer: 2, fraction: 1] | [42.1, 13.2] | [42.1, 3.14]
+ EachDigits | [integer: 2, fraction: 1] | ['42.1', '13.2'] | ['42.1', '3.14']
+ EachEAN | [type: Type.EAN8] | ['12345670'] | ['12345670', '123']
+ EachEmail | [:] | ['x@y.z', 'a@b.c'] | ['x@y.z', 'ab.c']
+ EachFuture | [:] | [futureDate()] | [pastDate()]
+ EachLength | [min: 1, max: 3] | ['a', 'foo'] | ['a', 'allons-y!']
+ EachLuhnCheck | [:] | ['79927398713'] | ['79927398714']
+ EachMax | [value: 3L] | [1, 2, 3] | [2, 3, 4]
+ EachMax | [value: 3L] | ['1', '2', '3'] | ['2', '3', '4']
+ EachMin | [value: 3L] | [3, 4, 5] | [1, 2, 3]
+ EachMin | [value: 3L] | ['3', '4', '5'] | ['1', '2', '3']
+ EachMod10Check | [:] | ['123'] | ['123', '124']
+ EachMod11Check | [:] | ['124'] | ['124', '125']
+ EachNotBlank | [:] | ['foo', 'bar'] | ['foo', '']
+ //EachNotEmpty | [:] | ['x', 'yz'] | ['x', ''] FIXME!
+ EachNotNull | [:] | ['foo', 'bar'] | ['foo', null]
+ EachPast | [:] | [pastDate()] | [futureDate()]
+ EachPattern | [regexp: '[A-Z]+'] | ['FOO', 'BAR'] | ['FOO', '123']
+ //EachRange | [min: 3L, max: 6L] | [3, 4, 5] | [6, 7, 8] FIXME!
+ EachSafeHtml | [:] | ['foo'] | ['WAT?']
+ EachSize | [min: 1, max: 2] | ['a', 'xy'] | ['a', 'foo']
+ EachSize | [min: 1, max: 2] | [[1], [2, 3]] | [[1], [2, 3, 4]]
+ EachSize | [min: 1, max: 2] | [[a: 1], [b: 2]] | [[a: 1], [:]]
+ EachURL | [protocol: 'https'] | ['https://nic.cz'] | ['http://nic.cz']
}
+ //////// Helpers ////////
+
+ static getEachConstraints() {
+ CONSTRAINTS_JSR + CONSTRAINTS_HV + (HV_VERSION >= 5_1_0 ? CONSTRAINTS_5_1_0 : [])
+ }
+
def attributesTypesSet(Class annotation) {
annotation.declaredMethods.collect(new HashSet()) { m ->
[m.name, m.returnType]
}
}
+
+ def futureDate() {
+ new Date().plus(1)
+ }
+
+ def pastDate() {
+ new Date().minus(1)
+ }
}