[#1158] Split a check-references-filter-criteria value at its first colon, so the filter can contain one (#1167)
Fixes #1158
## Problem
The referential integrity plugin split each
`check-references-filter-criteria` value (`attribute:filter`) at the
**last** colon, both when it validated the configuration and when it
applied it. An attribute description cannot contain `:`, but a filter
often does — a URN or URL value (`(o=urn:example)`), or an extensible
match (`(cn:dn:=x)`) — so such a value was refused: `member:(cn:dn` was
taken for the attribute and `=x)` for the filter.
There was a second, quieter difference between the two paths: only
validation trimmed the parts. `manager :(objectClass=person)` passed
validation, but the apply path looked up the attribute `"manager "`, got
a placeholder type, and the filter was never enforced.
## Fix
Both paths now call one helper, `splitFilterCriteria`, that splits at
the **first** colon and trims both parts. The property syntax
(`^[^:]+:\(.+\)$`) already guarantees a colon after a non-empty,
colon-free attribute, so the first colon is always the separator.
## Tests
`ReferentialIntegrityPluginTestCase`:
- `validConfigs` gains a configuration with `member:(o=urn:example)` and
`member:(cn:dn:=x)`.
- New `testEnforceIntegrityWithColonInFilter`, for
`manager:(description=urn:example:manager)`,
`manager:(description:caseExactMatch:=urn:example:manager)` and `manager
:(description=*manager)`: the configuration change is accepted, adding
an employee whose manager has no `description` is refused with
`CONSTRAINT_VIOLATION`, and it succeeds once the manager's `description`
is `urn:example:manager`.
Without the fix all four new cases fail: the colon cases because the
configuration is refused (`Unwilling to Perform`), and the
trailing-space case because the configuration is accepted but the filter
is not enforced (`expected [Constraint Violation] but found [Success]`).
With the fix the class passes 65/65.
## Follow-up
Two `check-references-filter-criteria` values for the same attribute
type are both accepted, but only one of them is enforced. This was
already true before this change and is tracked in #1172.