public static DualInputSemanticProperties addSourceFieldOffsets(
            DualInputSemanticProperties props,
            int numInputFields1,
            int numInputFields2,
            int offset1,
            int offset2) {

        DualInputSemanticProperties offsetProps = new DualInputSemanticProperties();

        // add offset to read fields on first input
        if (props.getReadFields(0) != null) {
            FieldSet offsetReadFields = new FieldSet();
            for (int r : props.getReadFields(0)) {
                offsetReadFields = offsetReadFields.addField(r + offset1);
            }
            offsetProps.addReadFields(0, offsetReadFields);
        }
        // add offset to read fields on second input
        if (props.getReadFields(1) != null) {
            FieldSet offsetReadFields = new FieldSet();
            for (int r : props.getReadFields(1)) {
                offsetReadFields = offsetReadFields.addField(r + offset2);
            }
            offsetProps.addReadFields(1, offsetReadFields);
        }

        // add offset to forward fields on first input
        for (int s = 0; s < numInputFields1; s++) {
            FieldSet targetFields = props.getForwardingTargetFields(0, s);
            for (int t : targetFields) {
                offsetProps.addForwardedField(0, s + offset1, t);
            }
        }
        // add offset to forward fields on second input
        for (int s = 0; s < numInputFields2; s++) {
            FieldSet targetFields = props.getForwardingTargetFields(1, s);
            for (int t : targetFields) {
                offsetProps.addForwardedField(1, s + offset2, t);
            }
        }

        return offsetProps;
    }
@Test
    void testAddSourceFieldOffsets() {

        DualInputSemanticProperties semProps = new DualInputSemanticProperties();
        semProps.addForwardedField(0, 0, 1);
        semProps.addForwardedField(0, 3, 3);
        semProps.addForwardedField(1, 1, 2);
        semProps.addForwardedField(1, 1, 4);
        semProps.addReadFields(0, new FieldSet(1, 2));
        semProps.addReadFields(1, new FieldSet(0, 3, 4));

        DualInputSemanticProperties offsetProps =
                SemanticPropUtil.addSourceFieldOffsets(semProps, 4, 3, 1, 2);

        assertThat(offsetProps.getForwardingTargetFields(0, 0)).isEmpty();
        assertThat(offsetProps.getForwardingTargetFields(0, 1)).containsExactly(1);
        assertThat(offsetProps.getForwardingTargetFields(0, 2)).isEmpty();
        assertThat(offsetProps.getForwardingTargetFields(0, 3)).isEmpty();
        assertThat(offsetProps.getForwardingTargetFields(0, 4)).containsExactly(3);

        assertThat(offsetProps.getForwardingTargetFields(1, 0)).isEmpty();
        assertThat(offsetProps.getForwardingTargetFields(1, 1)).isEmpty();
        assertThat(offsetProps.getForwardingTargetFields(1, 2)).isEmpty();
        assertThat(offsetProps.getForwardingTargetFields(1, 3)).containsExactly(4, 2);

        assertThat(offsetProps.getReadFields(0)).containsExactly(2, 3);
        assertThat(offsetProps.getReadFields(1)).containsExactly(2, 5, 6);

        semProps = new DualInputSemanticProperties();
        SemanticPropUtil.addSourceFieldOffsets(semProps, 4, 3, 2, 2);
    }