@Test
public void testRuleModelCloning() {

    RuleModel model = new RuleModel();
    //--------------------------------------------------------------------------------------------------------------
    // LHS
    //--------------------------------------------------------------------------------------------------------------
    //
    RuleAttribute attribute = new RuleAttribute( "att1_name", "att1_val" );
    model.addAttribute( attribute );
    RuleMetadata metadata = new RuleMetadata( "meta1_name", "meta1_val" );
    model.addMetadata( metadata );
    FactPattern f1 = buildFactPattern();
    FactPattern f2 = new FactPattern();
    f2.setBoundName( "$f2" );
    f2.setFactType( "Fact2" );
    f2.addConstraint( buildCompositeFieldConstraint() );
    CompositeFactPattern composite = new CompositeFactPattern();
    composite.setType( CompositeFactPattern.COMPOSITE_TYPE_EXISTS );
    composite.addFactPattern( f1 );
    composite.addFactPattern( f2 );
    model.addLhsItem( composite );
    model.addLhsItem( buildFromAccumulateCompositeFactPattern() );
    model.addLhsItem( buildFromCollectCompositeFactPattern() );
    model.addLhsItem( buildFromCompositeFactPattern() );
    model.addLhsItem( buildFreeFormLine() );
    model.addLhsItem( buildDslSentence() );
    ActionGlobalCollectionAdd addGlobal = new ActionGlobalCollectionAdd();
    addGlobal.setFactName( "MyFact" );
    addGlobal.setGlobalName( "glist" );
    model.addRhsItem( addGlobal );
    //--------------------------------------------------------------------------------------------------------------
    // RHS
    //--------------------------------------------------------------------------------------------------------------
    //
    ActionInsertFact aif = new ActionInsertFact();
    aif.setBoundName( "$f" );
    aif.setFactType( "FactType" );
    aif.addFieldValue( buildActionFieldValue() );
    aif.addFieldValue( buildActionFieldValue() );
    model.addRhsItem( aif );
    ActionUpdateField auf = new ActionUpdateField();
    auf.setVariable( "$var" );
    auf.addFieldValue( buildActionFieldValue() );
    auf.addFieldValue( buildActionFieldValue() );
    model.addRhsItem( auf );
    ActionSetField asf = new ActionSetField();
    asf.setVariable( "$var" );
    asf.addFieldValue( buildActionFieldValue() );
    asf.addFieldValue( buildActionFieldValue() );
    model.addRhsItem( asf );
    ActionRetractFact arf = new ActionRetractFact();
    arf.setVariableName( "$f" );
    model.addRhsItem( arf );
    ActionCallMethod callMethod1 = new ActionCallMethod();
    callMethod1.setVariable( "var1" );
    callMethod1.setMethodName( "testMethod1 " );
    callMethod1.setState( ActionCallMethod.TYPE_DEFINED );
    callMethod1.addFieldValue( new ActionFieldFunction( "field1", "value1", "type1" ) );
    model.addRhsItem( callMethod1 );
    ActionCallMethod callMethod2 = new ActionCallMethod();
    callMethod2.setVariable( "var2" );
    callMethod2.setMethodName( "testMethod2 " );
    callMethod2.setState( ActionCallMethod.TYPE_UNDEFINED );
    callMethod2.addFieldValue( new ActionFieldFunction( "field2", "value2", "type2" ) );
    model.addRhsItem( callMethod2 );
    model.addRhsItem( buildFreeFormLine() );
    //--------------------------------------------------------------------------------------------------------------
    // Clone and verify
    //--------------------------------------------------------------------------------------------------------------
    //
    RuleModel clone = new RuleModelCloneVisitor().visitRuleModel( model );
    assertArrayEquals( model.attributes, clone.attributes );
    int attIndex = 0;
    for ( RuleAttribute att : model.attributes ) {
        assertNotSame( att, clone.attributes[ attIndex++ ] );
    }
    assertArrayEquals( model.metadataList, clone.metadataList );
    int metIndex = 0;
    for ( RuleMetadata met : model.metadataList ) {
        assertNotSame( met, clone.metadataList[ metIndex++ ] );
    }
    assertArrayEquals( model.lhs, clone.lhs );
    int lhsIndex = 0;
    for ( IPattern pattern : model.lhs ) {
        assertNotSame( pattern, clone.lhs[ lhsIndex++ ] );
    }
    assertArrayEquals( model.rhs, clone.rhs );
    int rhsIndex = 0;
    for ( IAction action : model.rhs ) {
        assertNotSame( action, clone.rhs[ rhsIndex++ ] );
    }
}