private static boolean evaluatePayloadValidator(
      @Nonnull final RuleEvaluator ruleEvaluator, final String rule, @Nonnull final Payload payload)
      throws IncompatibleTestMatrixException {
    Map<String, Object> values = Collections.singletonMap("value", payload.fetchAValue());

    try {
      return ruleEvaluator.evaluateBooleanRule(rule, values);
    } catch (@Nonnull final IllegalArgumentException e) {
      LOGGER.error("Unable to evaluate rule ${" + rule + "} with payload " + payload, e);
    }

    return false;
  }
  public static void verifyInternallyConsistentDefinition(
      final String testName,
      final String matrixSource,
      @Nonnull final ConsumableTestDefinition testDefinition)
      throws IncompatibleTestMatrixException {
    final List<Allocation> allocations = testDefinition.getAllocations();
    if (allocations.isEmpty()) {
      throw new IncompatibleTestMatrixException("No allocations specified in test " + testName);
    }
    final List<TestBucket> buckets = testDefinition.getBuckets();

    /*
     * test the matrix for consistency with itself
     */
    final Set<Integer> definedBuckets = Sets.newHashSet();
    for (final TestBucket bucket : buckets) {
      definedBuckets.add(bucket.getValue());
    }

    for (final Allocation allocation : allocations) {
      final List<Range> ranges = allocation.getRanges();
      //  ensure that each range refers to a known bucket
      double bucketTotal = 0;
      for (final Range range : ranges) {
        bucketTotal += range.getLength();
        // Internally consistent (within matrix itself)
        if (!definedBuckets.contains(range.getBucketValue())) {
          throw new IncompatibleTestMatrixException(
              "Allocation range in "
                  + testName
                  + " from "
                  + matrixSource
                  + " refers to unknown bucket value "
                  + range.getBucketValue());
        }
      }
      //  I hate floating points.  TODO: extract a required precision constant/parameter?
      if (bucketTotal < 0.9999
          || bucketTotal
              > 1.0001) { //  compensate for FP imprecision.  TODO: determine what these bounds
                          // really should be by testing stuff
        final StringBuilder sb =
            new StringBuilder(
                    testName
                        + " range with rule "
                        + allocation.getRule()
                        + " does not add up to 1 : ")
                .append(ranges.get(0).getLength());
        for (int i = 1; i < ranges.size(); i++) {
          sb.append(" + ").append(ranges.get(i).getLength());
        }
        sb.append(" = ").append(bucketTotal);
        throw new IncompatibleTestMatrixException(sb.toString());
      }
    }
    final Allocation lastAllocation = allocations.get(allocations.size() - 1);
    if (!CharMatcher.WHITESPACE.matchesAllOf(Strings.nullToEmpty(lastAllocation.getRule()))) {
      throw new IncompatibleTestMatrixException(
          "Final allocation for test "
              + testName
              + " from "
              + matrixSource
              + " has non-empty rule: "
              + lastAllocation.getRule());
    }

    /*
     * When defined, within a single test, all test bucket payloads
     * should be supplied; they should all have just one type each,
     * and they should all be the same type.
     */
    Payload nonEmptyPayload = null;
    final List<TestBucket> bucketsWithoutPayloads = Lists.newArrayList();
    for (final TestBucket bucket : buckets) {
      final Payload p = bucket.getPayload();
      if (p != null) {
        if (p.numFieldsDefined() != 1) {
          throw new IncompatibleTestMatrixException(
              "Test "
                  + testName
                  + " from "
                  + matrixSource
                  + " has a test bucket payload with multiple types: "
                  + bucket);
        }
        if (nonEmptyPayload == null) {
          nonEmptyPayload = p;
        } else if (!nonEmptyPayload.sameType(p)) {
          throw new IncompatibleTestMatrixException(
              "Test "
                  + testName
                  + " from "
                  + matrixSource
                  + " has test bucket: "
                  + bucket
                  + " incompatible with type of payload: "
                  + nonEmptyPayload);
        }
      } else {
        bucketsWithoutPayloads.add(bucket);
      }
    }
    if ((nonEmptyPayload != null) && (bucketsWithoutPayloads.size() != 0)) {
      throw new IncompatibleTestMatrixException(
          "Test "
              + testName
              + " from "
              + matrixSource
              + " has some test buckets without payloads: "
              + bucketsWithoutPayloads);
    }
  }