@Override
    public Predicate negate() {
        int size = predicates.length;
        Predicate[] inners = new Predicate[size];
        for (int i = 0; i < size; i++) {
            Predicate original = predicates[i];
            Predicate negated;
            if (original instanceof NegatablePredicate predicate) {
                negated = predicate.negate();
            } else {
                negated = new NotPredicate(original);
            }
            inners[i] = negated;
        }
        AndPredicate andPredicate = new AndPredicate(inners);
        return andPredicate;
    }
@Test
    public void negate_whenContainsNonNegatablePredicate_thenReturnAndPredicateWithNotInside() {
        // ~(foo or bar)  -->  (~foo and ~bar)
        // this is testing the case where the inner predicate does NOT implement {@link Negatable}

        Predicate nonNegatable = mock(Predicate.class);

        OrPredicate or = (OrPredicate) or(nonNegatable);
        AndPredicate result = (AndPredicate) or.negate();

        Predicate[] inners = result.predicates;
        assertThat(inners).hasSize(1);

        NotPredicate notPredicate = (NotPredicate) inners[0];
        assertThat(nonNegatable).isSameAs(notPredicate.predicate);
    }