build-test-data
build-test-data copied to clipboard
ValidateableDataBuilder#satisfyConstrained and unique vs. nullable vs. blank
given a domain
class Foo {
String name
static constraints = {
name blank: false, unique: true
}
}
and a spec
@Build(Foo)
class FooSpec extends Specification implements DomainUnitTest<Foo>, BuildDataTest {
def "test blank 'x' vs. unique constraint"() {
when:
Foo.build()
Foo.build()
Foo.build()
currentSession.flush()
then:
def e = thrown(ValidationException)
e.errors.getFieldError("name").rejectedValue == "name"
}
}
fails with
Condition not satisfied:
e.errors.getFieldError("name").rejectedValue == "name"
| | | | |
| | | x false
| | | 4 differences (0% similarity)
| | | (x---)
| | | (name)
| | Field error in object 'myapp.Foo' on field 'name': rejected value [x]; codes [myapp.Foo.name.unique.error.myapp.Foo.name,myapp.Foo.name.unique.error.name,myapp.Foo.name.unique.error.java.lang.String,myapp.Foo.name.unique.error,foo.name.unique.error.myapp.Foo.name,foo.name.unique.error.name,foo.name.unique.error.java.lang.String,foo.name.unique.error,myapp.Foo.name.unique.myapp.Foo.name,myapp.Foo.name.unique.name,myapp.Foo.name.unique.java.lang.String,myapp.Foo.name.unique,foo.name.unique.myapp.Foo.name,foo.name.unique.name,foo.name.unique.java.lang.String,foo.name.unique,unique.myapp.Foo.name,unique.name,unique.java.lang.String,unique]; arguments [name,class myapp.Foo,x]; default message [null]
| org.grails.datastore.mapping.validation.ValidationErrors: 1 errors
| Field error in object 'myapp.Foo' on field 'name': rejected value [x]; codes [myapp.Foo.name.unique.error.myapp.Foo.name,myapp.Foo.name.unique.error.name,myapp.Foo.name.unique.error.java.lang.String,myapp.Foo.name.unique.error,foo.name.unique.error.myapp.Foo.name,foo.name.unique.error.name,foo.name.unique.error.java.lang.String,foo.name.unique.error,myapp.Foo.name.unique.myapp.Foo.name,myapp.Foo.name.unique.name,myapp.Foo.name.unique.java.lang.String,myapp.Foo.name.unique,foo.name.unique.myapp.Foo.name,foo.name.unique.name,foo.name.unique.java.lang.String,foo.name.unique,unique.myapp.Foo.name,unique.name,unique.java.lang.String,unique]; arguments [name,class myapp.Foo,x]; default message [null]
grails.validation.ValidationException: Validation error occurred during call to save():
- Field error in object 'myapp.Foo' on field 'name': rejected value [x]; codes [myapp.Foo.name.unique.error.myapp.Foo.name,myapp.Foo.name.unique.error.name,myapp.Foo.name.unique.error.java.lang.String,myapp.Foo.name.unique.error,foo.name.unique.error.myapp.Foo.name,foo.name.unique.error.name,foo.name.unique.error.java.lang.String,foo.name.unique.error,myapp.Foo.name.unique.myapp.Foo.name,myapp.Foo.name.unique.name,myapp.Foo.name.unique.java.lang.String,myapp.Foo.name.unique,foo.name.unique.myapp.Foo.name,foo.name.unique.name,foo.name.unique.java.lang.String,foo.name.unique,unique.myapp.Foo.name,unique.name,unique.java.lang.String,unique]; arguments [name,class myapp.Foo,x]; default message [null]
Expected :name
Actual :x
log:
2018-05-29 08:16:11.773 DEBUG --- [ main] g.b.builders.ValidateableDataBuilder : myapp.Foo.nullable constraint, field before adjustment: null
2018-05-29 08:16:11.775 DEBUG --- [ main] g.b.builders.ValidateableDataBuilder : myapp.Foo.name field after adjustment for nullable: name
2018-05-29 08:16:11.982 DEBUG --- [ main] g.b.builders.ValidateableDataBuilder : myapp.Foo.nullable constraint, field before adjustment: null
2018-05-29 08:16:11.982 DEBUG --- [ main] g.b.builders.ValidateableDataBuilder : myapp.Foo.name field after adjustment for nullable: name
2018-05-29 08:16:11.992 DEBUG --- [ main] g.b.builders.ValidateableDataBuilder : myapp.Foo.blank constraint, field before adjustment: name
2018-05-29 08:16:11.992 DEBUG --- [ main] g.b.builders.ValidateableDataBuilder : myapp.Foo.name field after adjustment for blank: x
2018-05-29 08:16:11.993 DEBUG --- [ main] g.b.builders.ValidateableDataBuilder : myapp.Foo.nullable constraint, field before adjustment: null
2018-05-29 08:16:11.993 DEBUG --- [ main] g.b.builders.ValidateableDataBuilder : myapp.Foo.name field after adjustment for nullable: name
2018-05-29 08:16:11.995 DEBUG --- [ main] g.b.builders.ValidateableDataBuilder : myapp.Foo.blank constraint, field before adjustment: name
2018-05-29 08:16:11.995 DEBUG --- [ main] g.b.builders.ValidateableDataBuilder : myapp.Foo.name field after adjustment for blank: x
2018-05-29 08:16:11.995 DEBUG --- [ main] g.b.builders.ValidateableDataBuilder : myapp.Foo.unique constraint, field before adjustment: x
2018-05-29 08:16:11.995 WARN --- [ main] g.b.builders.ValidateableDataBuilder : Unable to find property generator handler for constraint unique!
- first
Foo.build()name: "name" - unique - constraints satisfied
- second
Foo.build()name: "x" - unique - constraints satisfied
- third
Foo.build()name: "x" - not unique - constraints not satisfied
so when the unique constraint is not satisfied, the BlankConstraintHandler gets applied, that was unexpected.
as we have to take care of proper unique value generation anyway this is not blocking. just that the second build() passed and then the third fails with a value of x instead with the unique propertyName name is confusing.
referencing sample app in a minute.
@zyro23 Thanks for the sample app. I'll take a look.