protected void declareConstraintsXor(final List<KiePMMLFieldOperatorValue> xorConstraints) {
        if (xorConstraints.size() != 2) {
            throw new KiePMMLException("Expecting two fields for XOR constraints, retrieved " + xorConstraints.size());
        }
        final String[] keys = new String[xorConstraints.size()];
        final String[] values = new String[xorConstraints.size()];
        for (int i = 0; i < keys.length; i++) {
            keys[i] = xorConstraints.get(i).getName();
            values[i] = xorConstraints.get(i).getConstraintsAsString();
        }
        final CEDescrBuilder<CEDescrBuilder<RuleDescrBuilder, AndDescr>, AndDescr> andBuilder = builder.and();
        final CEDescrBuilder<CEDescrBuilder<CEDescrBuilder<CEDescrBuilder<RuleDescrBuilder, AndDescr>, AndDescr>, NotDescr>, AndDescr> notBuilder = andBuilder.not().and();
        commonDeclarePatternWithConstraint(notBuilder, keys[0], values[0]);
        commonDeclarePatternWithConstraint(notBuilder, keys[1], values[1]);
        final CEDescrBuilder<CEDescrBuilder<CEDescrBuilder<CEDescrBuilder<RuleDescrBuilder, AndDescr>, AndDescr>, ExistsDescr>, OrDescr> existsBuilder = andBuilder.exists().or();
        commonDeclarePatternWithConstraint(existsBuilder, keys[0], values[0]);
        commonDeclarePatternWithConstraint(existsBuilder.or(), keys[1], values[1]);
    }
@Test
    void declareConstraintsXor() {
        String temperatureField = "TEMPERATURE";
        final List<KiePMMLFieldOperatorValue> xorConstraints = Arrays
                .asList(new KiePMMLFieldOperatorValue(temperatureField, BOOLEAN_OPERATOR.OR,
                                Collections.singletonList(new KiePMMLOperatorValue(OPERATOR.LESS_THAN, 35)), null),
                        new KiePMMLFieldOperatorValue(temperatureField, BOOLEAN_OPERATOR.OR,
                                Collections.singletonList(new KiePMMLOperatorValue(OPERATOR.GREATER_THAN, 85)), null));
        KiePMMLDescrLhsFactory.factory(lhsBuilder).declareConstraintsXor(xorConstraints);
        assertThat(lhsBuilder.getDescr()).isNotNull();
        assertThat(lhsBuilder.getDescr().getDescrs()).isNotNull();
        assertThat(lhsBuilder.getDescr().getDescrs()).hasSize(1);
        assertThat(lhsBuilder.getDescr().getDescrs().get(0)).isInstanceOf(AndDescr.class);
        AndDescr rootAndDescr = (AndDescr) lhsBuilder.getDescr().getDescrs().get(0);
        assertThat(rootAndDescr.getDescrs()).hasSize(2);
        assertThat(rootAndDescr.getDescrs().get(0)).isInstanceOf(NotDescr.class);
        assertThat(rootAndDescr.getDescrs().get(1)).isInstanceOf(ExistsDescr.class);
        // "Not" construct
        NotDescr notDescr = (NotDescr) rootAndDescr.getDescrs().get(0);
        assertThat(notDescr.getDescrs()).hasSize(1);
        assertThat(notDescr.getDescrs().get(0)).isInstanceOf(AndDescr.class);
        AndDescr notAndDescr = (AndDescr) notDescr.getDescrs().get(0);
        assertThat(notAndDescr.getDescrs().get(0)).isInstanceOf(PatternDescr.class);
        assertThat(notAndDescr.getDescrs().get(1)).isInstanceOf(PatternDescr.class);
        PatternDescr patternDescr = (PatternDescr) notAndDescr.getDescrs().get(0);
        assertThat(patternDescr.getObjectType()).isEqualTo(temperatureField);
        assertThat(patternDescr.getIdentifier()).isNull();
        assertThat(patternDescr.getConstraint()).isInstanceOf(AndDescr.class);
        AndDescr andDescr = (AndDescr) patternDescr.getConstraint();
        assertThat(andDescr.getDescrs()).hasSize(1);
        assertThat(andDescr.getDescrs().get(0)).isInstanceOf(ExprConstraintDescr.class);
        ExprConstraintDescr exprConstraintDescr = (ExprConstraintDescr) andDescr.getDescrs().get(0);
        assertThat(exprConstraintDescr.isNegated()).isFalse();
        assertThat(exprConstraintDescr.getType()).isEqualTo(ExprConstraintDescr.Type.NAMED);
        String expected = "value < 35";
        assertThat(exprConstraintDescr.getExpression()).isEqualTo(expected);
        patternDescr = (PatternDescr) notAndDescr.getDescrs().get(1);
        assertThat(patternDescr.getObjectType()).isEqualTo(temperatureField);
        assertThat(patternDescr.getIdentifier()).isNull();
        assertThat(patternDescr.getConstraint()).isInstanceOf(AndDescr.class);
        andDescr = (AndDescr) patternDescr.getConstraint();
        assertThat(andDescr.getDescrs()).hasSize(1);
        assertThat(andDescr.getDescrs().get(0)).isInstanceOf(ExprConstraintDescr.class);
        exprConstraintDescr = (ExprConstraintDescr) andDescr.getDescrs().get(0);
        assertThat(exprConstraintDescr.isNegated()).isFalse();
        assertThat(exprConstraintDescr.getType()).isEqualTo(ExprConstraintDescr.Type.NAMED);
        expected = "value > 85";
        assertThat(exprConstraintDescr.getExpression()).isEqualTo(expected);
        // "Exists" construct
        ExistsDescr existsDescr = (ExistsDescr) rootAndDescr.getDescrs().get(1);
        assertThat(existsDescr.getDescrs()).hasSize(1);
        assertThat(existsDescr.getDescrs().get(0)).isInstanceOf(OrDescr.class);
        OrDescr existsOrDescr = (OrDescr) existsDescr.getDescrs().get(0);
        assertThat(existsOrDescr.getDescrs()).hasSize(2);
        assertThat(existsOrDescr.getDescrs().get(0)).isInstanceOf(PatternDescr.class);
        assertThat(existsOrDescr.getDescrs().get(1)).isInstanceOf(OrDescr.class);
        patternDescr = (PatternDescr) existsOrDescr.getDescrs().get(0);
        assertThat(patternDescr.getObjectType()).isEqualTo(temperatureField);
        assertThat(patternDescr.getIdentifier()).isNull();
        assertThat(patternDescr.getConstraint()).isInstanceOf(AndDescr.class);
        andDescr = (AndDescr) patternDescr.getConstraint();
        assertThat(andDescr.getDescrs()).hasSize(1);
        assertThat(andDescr.getDescrs().get(0)).isInstanceOf(ExprConstraintDescr.class);
        exprConstraintDescr = (ExprConstraintDescr) andDescr.getDescrs().get(0);
        assertThat(exprConstraintDescr.isNegated()).isFalse();
        assertThat(exprConstraintDescr.getType()).isEqualTo(ExprConstraintDescr.Type.NAMED);
        expected = "value < 35";
        assertThat(exprConstraintDescr.getExpression()).isEqualTo(expected);
        OrDescr nestedOrDescr = (OrDescr) existsOrDescr.getDescrs().get(1);
        assertThat(nestedOrDescr.getDescrs()).hasSize(1);
        assertThat(nestedOrDescr.getDescrs().get(0)).isInstanceOf(PatternDescr.class);
        patternDescr = (PatternDescr) nestedOrDescr.getDescrs().get(0);
        assertThat(patternDescr.getObjectType()).isEqualTo(temperatureField);
        assertThat(patternDescr.getIdentifier()).isNull();
        assertThat(patternDescr.getConstraint()).isInstanceOf(AndDescr.class);
        andDescr = (AndDescr) patternDescr.getConstraint();
        assertThat(andDescr.getDescrs()).hasSize(1);
        assertThat(andDescr.getDescrs().get(0)).isInstanceOf(ExprConstraintDescr.class);
        exprConstraintDescr = (ExprConstraintDescr) andDescr.getDescrs().get(0);
        assertThat(exprConstraintDescr.isNegated()).isFalse();
        assertThat(exprConstraintDescr.getType()).isEqualTo(ExprConstraintDescr.Type.NAMED);
        expected = "value > 85";
        assertThat(exprConstraintDescr.getExpression()).isEqualTo(expected);
    }