/** Test the normalization and the middle substring match. */
  @Test(dataProvider = "substringMiddleMatchData")
  public void middleMatchingRules(
      final String value, final String[] middleSubs, final ConditionResult result)
      throws Exception {
    final MatchingRule rule = getRule();

    // normalize the 2 provided values and check that they are equals
    final ByteString normalizedValue = rule.normalizeAttributeValue(ByteString.valueOf(value));

    final StringBuilder printableMiddleSubs = new StringBuilder();
    final List<ByteSequence> middleList = new ArrayList<>(middleSubs.length);
    printableMiddleSubs.append("*");
    for (final String middleSub : middleSubs) {
      printableMiddleSubs.append(middleSub);
      printableMiddleSubs.append("*");
      middleList.add(ByteString.valueOf(middleSub));
    }

    final ConditionResult substringAssertionMatches =
        rule.getSubstringAssertion(null, middleList, null).matches(normalizedValue);
    final ConditionResult assertionMatches =
        rule.getAssertion(ByteString.valueOf(printableMiddleSubs)).matches(normalizedValue);
    final String message = getMessage("middle", rule, value, printableMiddleSubs.toString());
    assertEquals(substringAssertionMatches, result, message);
    assertEquals(assertionMatches, result, message);
  }
  /** Test that invalid values are rejected. */
  @Test(
      expectedExceptions = DecodeException.class,
      dataProvider = "substringInvalidAttributeValues")
  public void substringInvalidAttributeValues(final String value) throws Exception {
    // Get the instance of the rule to be tested.
    final MatchingRule rule = getRule();

    rule.normalizeAttributeValue(ByteString.valueOf(value));
  }
  /** Test the normalization and the final substring match. */
  @Test(dataProvider = "substringFinalMatchData")
  public void finalMatchingRules(
      final String value, final String finalValue, final ConditionResult result) throws Exception {
    final MatchingRule rule = getRule();

    // normalize the 2 provided values and check that they are equals
    final ByteString normalizedValue = rule.normalizeAttributeValue(ByteString.valueOf(value));

    final ConditionResult substringAssertionMatches =
        rule.getSubstringAssertion(null, null, ByteString.valueOf(finalValue))
            .matches(normalizedValue);
    final ConditionResult assertionMatches =
        rule.getAssertion(ByteString.valueOf("*" + finalValue)).matches(normalizedValue);
    final String message = getMessage("final", rule, value, finalValue);
    assertEquals(substringAssertionMatches, result, message);
    assertEquals(assertionMatches, result, message);
  }
  /** Test that invalid values are rejected. */
  @Test(
      expectedExceptions = DecodeException.class,
      dataProvider = "substringInvalidAssertionValues")
  public void matchingRulesInvalidAssertionValues(
      final String subInitial, final String[] anys, final String subFinal) throws Exception {
    // Get the instance of the rule to be tested.
    final MatchingRule rule = getRule();

    final List<ByteSequence> anyList = new ArrayList<>(anys.length);
    for (final String middleSub : anys) {
      anyList.add(ByteString.valueOf(middleSub));
    }
    rule.getSubstringAssertion(
        subInitial == null ? null : ByteString.valueOf(subInitial),
        anyList,
        subFinal == null ? null : ByteString.valueOf(subFinal));
  }
  /** Test that invalid values are rejected. */
  @Test(
      expectedExceptions = DecodeException.class,
      dataProvider = "substringInvalidAssertionValues")
  public void matchingRulesInvalidAssertionValuesString(
      final String subInitial, final String[] anys, final String subFinal) throws Exception {
    // Get the instance of the rule to be tested.
    final MatchingRule rule = getRule();

    final StringBuilder assertionString = new StringBuilder();
    if (subInitial != null) {
      assertionString.append(subInitial);
    }
    assertionString.append("*");
    for (final String middleSub : anys) {
      assertionString.append(middleSub);
      assertionString.append("*");
    }
    if (subFinal != null) {
      assertionString.append(subFinal);
    }
    rule.getAssertion(ByteString.valueOf(assertionString.toString()));
  }
 // if typeQName is null, we skip the rule-type correspondence test
 @NotNull
 public <T> MatchingRule<T> getMatchingRule(QName ruleName, QName typeQName)
     throws SchemaException {
   if (ruleName == null) {
     return (MatchingRule<T>) defaultMatchingRule;
   }
   MatchingRule<T> matchingRule = (MatchingRule<T>) matchingRules.get(ruleName);
   if (matchingRule == null) {
     // try match according to the localPart
     if (QNameUtil.matchAny(ruleName, matchingRules.keySet())) {
       ruleName = QNameUtil.resolveNs(ruleName, matchingRules.keySet());
       matchingRule = (MatchingRule<T>) matchingRules.get(ruleName);
     }
     if (matchingRule == null) {
       throw new SchemaException("Unknown matching rule for name " + ruleName);
     }
   }
   if (typeQName != null && !matchingRule.isSupported(typeQName)) {
     throw new SchemaException(
         "Matching rule " + ruleName + " does not support type " + typeQName);
   }
   return matchingRule;
 }
 public <T> void registerMatchingRule(MatchingRule<T> rule) {
   ((Map) this.matchingRules).put(rule.getName(), rule);
 }