Package org.drools.reteoo.test

Source Code of org.drools.reteoo.test.ReteDslTestEngine$LeftTupleComparator

/*
* Copyright 2010 JBoss Inc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*      http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.drools.reteoo.test;

import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import junit.framework.AssertionFailedError;

import org.antlr.runtime.ANTLRInputStream;
import org.antlr.runtime.ANTLRReaderStream;
import org.antlr.runtime.ANTLRStringStream;
import org.antlr.runtime.CommonTokenStream;
import org.antlr.runtime.RecognitionException;
import org.antlr.runtime.TokenStream;
import org.antlr.runtime.tree.CommonTree;
import org.antlr.runtime.tree.CommonTreeNodeStream;
import org.antlr.runtime.tree.Tree;
import org.drools.RuleBaseConfiguration;
import org.drools.common.DefaultFactHandle;
import org.drools.common.InternalFactHandle;
import org.drools.common.InternalWorkingMemory;
import org.drools.common.PropagationContextImpl;
import org.drools.core.util.Iterator;
import org.drools.core.util.ObjectHashMap;
import org.drools.core.util.ObjectHashMap.ObjectEntry;
import org.drools.reteoo.AccumulateNode;
import org.drools.reteoo.AccumulateNode.AccumulateMemory;
import org.drools.reteoo.BetaMemory;
import org.drools.reteoo.BetaNode;
import org.drools.reteoo.LeftTuple;
import org.drools.reteoo.LeftTupleImpl;
import org.drools.reteoo.LeftTupleMemory;
import org.drools.reteoo.LeftTupleSink;
import org.drools.reteoo.ModifyPreviousTuples;
import org.drools.reteoo.ObjectSink;
import org.drools.reteoo.ObjectTypeNode;
import org.drools.reteoo.ReteooRuleBase;
import org.drools.reteoo.RightInputAdapterNode;
import org.drools.reteoo.RightInputAdapterNode.RiaNodeMemory;
import org.drools.reteoo.RightTuple;
import org.drools.reteoo.RightTupleMemory;
import org.drools.reteoo.RuleTerminalNode;
import org.drools.reteoo.Sink;
import org.drools.reteoo.builder.BuildContext;
import org.drools.reteoo.test.dsl.AccumulateNodeStep;
import org.drools.reteoo.test.dsl.BetaNodeStep;
import org.drools.reteoo.test.dsl.BindingStep;
import org.drools.reteoo.test.dsl.ConfigStep;
import org.drools.reteoo.test.dsl.DSLMock;
import org.drools.reteoo.test.dsl.DslStep;
import org.drools.reteoo.test.dsl.EvalNodeStep;
import org.drools.reteoo.test.dsl.ExistsNodeStep;
import org.drools.reteoo.test.dsl.FactsStep;
import org.drools.reteoo.test.dsl.JoinNodeStep;
import org.drools.reteoo.test.dsl.LeftInputAdapterNodeStep;
import org.drools.reteoo.test.dsl.LeftTupleSinkStep;
import org.drools.reteoo.test.dsl.MockitoHelper;
import org.drools.reteoo.test.dsl.NodeTestCase;
import org.drools.reteoo.test.dsl.NodeTestCaseResult;
import org.drools.reteoo.test.dsl.NodeTestCaseResult.NodeTestResult;
import org.drools.reteoo.test.dsl.NodeTestCaseResult.Result;
import org.drools.reteoo.test.dsl.NodeTestDef;
import org.drools.reteoo.test.dsl.NotNodeStep;
import org.drools.reteoo.test.dsl.ObjectTypeNodeStep;
import org.drools.reteoo.test.dsl.RIANodeStep;
import org.drools.reteoo.test.dsl.ReteTesterHelper;
import org.drools.reteoo.test.dsl.RuleTerminalNodeStep;
import org.drools.reteoo.test.dsl.Step;
import org.drools.reteoo.test.dsl.WithStep;
import org.drools.reteoo.test.parser.NodeTestDSLLexer;
import org.drools.reteoo.test.parser.NodeTestDSLParser;
import org.drools.reteoo.test.parser.NodeTestDSLParser.compilation_unit_return;
import org.drools.reteoo.test.parser.NodeTestDSLTree;
import org.drools.rule.MVELDialectRuntimeData;
import org.drools.rule.Rule;
import org.drools.spi.PropagationContext;
import org.junit.runner.Description;
import org.junit.runner.notification.Failure;
import org.junit.runner.notification.RunNotifier;
import org.junit.runner.notification.StoppedByUserException;
import org.mvel2.MVEL;

public class ReteDslTestEngine {

    public static final String  WORKING_MEMORY           = "WorkingMemory";
    public static final String  BUILD_CONTEXT            = "BuildContext";
    private static final String CONFIG                   = "Config";
    private static final String OBJECT_TYPE_NODE         = "ObjectTypeNode";
    private static final String LEFT_INPUT_ADAPTER_NODE  = "LeftInputAdapterNode";
    private static final String BINDING                  = "Binding";
    private static final String JOIN_NODE                = "JoinNode";
    private static final String NOT_NODE                 = "NotNode";
    private static final String EXISTS_NODE              = "ExistsNode";
    private static final String ACCUMULATE_NODE          = "AccumulateNode";
    private static final String RULE_TERMINAL_NODE       = "RuleTerminalNode";
    private static final String EVAL_NODE                = "EvalNode";
    private static final String WITH                     = "With";
    private static final String FACTS                    = "Facts";
    private static final String RIGHT_INPUT_ADAPTER_NODE = "RightInputAdapterNode";
    private static final String LEFT_TUPLE_SINK_STEP     = "LeftTupleSink";
    private static final String BETA_NODE_STEP           = "BetaNodeStep";

    private ReteTesterHelper    reteTesterHelper;
    private Map<String, Object> steps;

    public ReteDslTestEngine() {

        this.reteTesterHelper = new ReteTesterHelper();

        this.steps = new HashMap<String, Object>();

        this.steps.put( CONFIG,
                        new ConfigStep() );
        this.steps.put( OBJECT_TYPE_NODE,
                        new ObjectTypeNodeStep( this.reteTesterHelper ) );
        this.steps.put( LEFT_INPUT_ADAPTER_NODE,
                        new LeftInputAdapterNodeStep( this.reteTesterHelper ) );
        this.steps.put( BINDING,
                        new BindingStep( this.reteTesterHelper ) );
        this.steps.put( JOIN_NODE,
                        new JoinNodeStep( this.reteTesterHelper ) );
        this.steps.put( NOT_NODE,
                        new NotNodeStep( this.reteTesterHelper ) );
        this.steps.put( EXISTS_NODE,
                        new ExistsNodeStep( this.reteTesterHelper ) );
        this.steps.put( ACCUMULATE_NODE,
                        new AccumulateNodeStep( this.reteTesterHelper ) );
        this.steps.put( RULE_TERMINAL_NODE,
                        new RuleTerminalNodeStep( this.reteTesterHelper ) );
        this.steps.put( EVAL_NODE,
                        new EvalNodeStep( this.reteTesterHelper ) );
        this.steps.put( RIGHT_INPUT_ADAPTER_NODE,
                        new RIANodeStep( this.reteTesterHelper ) );
        this.steps.put( FACTS,
                        new FactsStep( this.reteTesterHelper ) );
        this.steps.put( WITH,
                        new WithStep( this.reteTesterHelper ) );
        this.steps.put( LEFT_TUPLE_SINK_STEP,
                        new LeftTupleSinkStep( this.reteTesterHelper ) );
        this.steps.put( BETA_NODE_STEP,
                        new BetaNodeStep( this.reteTesterHelper ) );
    }

    public NodeTestCaseResult run(NodeTestCase testCase,
                                  RunNotifier notifier) {
        if ( testCase == null || testCase.hasErrors() ) {
            throw new IllegalArgumentException( "Impossible to execute test case due to existing errors: " + testCase.getErrors() );
        }
        if ( notifier == null ) {
            notifier = EmptyNotifier.INSTANCE;
        }
        this.reteTesterHelper.addImports( testCase.getImports() );
        NodeTestCaseResult result = new NodeTestCaseResult( testCase );
        for ( NodeTestDef test : testCase.getTests() ) {
            notifier.fireTestStarted( test.getDescription() );
            NodeTestResult testResult = createTestResult( test,
                                                          null );

            try {
                testResult = run( testCase,
                                  test );

                switch ( testResult.result ) {
                    case SUCCESS :
                        notifier.fireTestFinished( test.getDescription() );
                        break;
                    case ERROR :
                    case FAILURE :
                        notifier.fireTestFailure( new Failure( test.getDescription(),
                                                               new AssertionError( testResult.errorMsgs ) ) );
                        break;
                }

            } catch ( Throwable e ) {
                notifier.fireTestFailure( new Failure( test.getDescription(),
                                                       e ) );
            }
            result.add( testResult );
        }
   
        return result;
    }

    private NodeTestResult run(NodeTestCase testCase,
                               NodeTestDef test) {
        Map<String, Object> context = createContext( testCase );
        NodeTestResult result = createTestResult( test,
                                                  context );

        try {
            // run setup
            run( context,
                 testCase.getSetup(),
                 result );
            // run test
            run( context,
                 test.getSteps(),
                 result );
            // run tearDown
            run( context,
                 testCase.getTearDown(),
                 result );
            result.result = Result.SUCCESS;
        } catch ( Throwable e ) {
            result.result = Result.ERROR;
            result.errorMsgs.add( e.toString() );
        }
        return result;
    }
   
    private NodeTestResult createTestResult(NodeTestDef test,
                                            Map<String, Object> context) {
       
        NodeTestResult result = new NodeTestResult( test,
                                                    Result.NOT_EXECUTED,
                                                    context,
                                                    new LinkedList<String>() );
        return result;
    }
   

    private Map<String, Object> createContext(NodeTestCase testCase) {
        Map<String, Object> context = new HashMap<String, Object>();
        context.put( "TestCase",
                     testCase );

        RuleBaseConfiguration conf = new RuleBaseConfiguration();

        ReteooRuleBase rbase = new ReteooRuleBase( "ID",
                                                   conf );
        BuildContext buildContext = new BuildContext( rbase,
                                                      rbase.getReteooBuilder().getIdGenerator() );

        Rule rule = new Rule("rule1", "org.pkg1", null);
        org.drools.rule.Package pkg = new org.drools.rule.Package( "org.pkg1" );
        pkg.getDialectRuntimeRegistry().setDialectData( "mvel", new MVELDialectRuntimeData() );
        pkg.addRule( rule );
       
        buildContext.setRule( rule );       
       
        rbase.addPackage( pkg );
        context.put( BUILD_CONTEXT,
                     buildContext );
        context.put( "ClassFieldAccessorStore",
                     this.reteTesterHelper.getStore() );

        InternalWorkingMemory wm = (InternalWorkingMemory) rbase.newStatefulSession( true );
        context.put( WORKING_MEMORY,
                     wm );
        return context;
    }

    public Map<String, Object> run(Map<String, Object> context,
                                   List<DslStep> steps,
                                   NodeTestResult result) {
        InternalWorkingMemory wm = (InternalWorkingMemory) context.get( WORKING_MEMORY );
        for ( DslStep step : steps ) {
            String name = step.getName();
            Object object = this.steps.get( name );
            if ( object != null && object instanceof Step ) {
                Step stepImpl = (Step) object;
                try {
                    stepImpl.execute( context,
                                      step.getCommands() );
                } catch ( Exception e ) {
                    throw new IllegalArgumentException( "line " + step.getLine() + ": unable to execute step " + step,
                                                        e );
                }
            } else if ( "assert".equals( name.trim() ) ) {
                assertObject( step,
                              context,
                              wm );
            } else if ( "retract".equals( name.trim() ) ) {
                retractObject( step,
                               context,
                               wm );
            } else if ( "modify".equals( name.trim() ) ) {
                modifyObject( step,
                              context,
                              wm );
            } else {
                Object node = context.get( name.trim() );
                if ( node == null ) {
                    throw new IllegalArgumentException( "line " + step.getLine() + ": step " + name + " does not exist" );
                }

                if ( node instanceof DSLMock ) {
                    // it is a mock
                    MockitoHelper.process( step,
                                           (LeftTupleSink) node,
                                           context,
                                           wm );
                } else if ( node instanceof BetaNode ) {
                    betaNode( step,
                              (BetaNode) node,
                              context,
                              wm );
                } else if ( node instanceof RightInputAdapterNode ) {
                    riaNode( step,
                             (RightInputAdapterNode) node,
                             context,
                             wm );
                } else if ( node instanceof RuleTerminalNode ) {
                    ruleTerminalNode( step,
                                      (RuleTerminalNode) node,
                                      context,
                                      wm );
                } else {
                    throw new IllegalArgumentException( "line " + step.getLine() + ": unknown node " + node );
                }
            }
        }

        return context;
    }

    private void betaNode(DslStep step,
                          BetaNode node,
                          Map<String, Object> context,
                          InternalWorkingMemory wm) {
       
        final boolean lrUnlinkingEnabled = ((BuildContext) context
                .get( BUILD_CONTEXT )).getRuleBase().getConfiguration()
                .isUnlinkingEnabled();

        try {
            List<String[]> cmds = step.getCommands();
            List<InternalFactHandle> handles = (List<InternalFactHandle>) context.get( "Handles" );

            BetaMemory memory = null;
            if ( node instanceof AccumulateNode ) {
                AccumulateMemory accmem = (AccumulateMemory) wm.getNodeMemory( node );
                memory = accmem.betaMemory;
            } else {
                memory = (BetaMemory) wm.getNodeMemory( node );
            }
            for ( String[] cmd : cmds ) {
                if ( cmd[0].equals( "leftMemory" ) ) {
                    String args = cmd[1];
                    String listString = args.replaceAll( "h(\\d+)",
                                                         "h[$1]" );
                    Map<String, Object> vars = new HashMap<String, Object>();
                    vars.put( "h",
                              handles );
                    List< ? > expectedLeftTuples = (List< ? >) MVEL.eval( listString,
                                                                          vars );

                    LeftTupleMemory leftMemory = memory.getLeftTupleMemory();

                    if ( expectedLeftTuples.isEmpty() && leftMemory.size() != 0 ) {
                        throw new AssertionFailedError( "line " + step.getLine()
                                                        + ": left Memory expected [] actually "
                                                        + print( leftMemory,
                                                                 lrUnlinkingEnabled ) );
                    } else if ( expectedLeftTuples.isEmpty()
                                && leftMemory.size() == 0 ) {
                        continue;
                       
                    }

                    // we always lookup from the first element, in case it's indexed
                    List<InternalFactHandle> first = (List<InternalFactHandle>) expectedLeftTuples.get( 0 );
                    LeftTuple firstTuple = new LeftTupleImpl( first.get( 0 ),
                                                              null,
                                                              false);
                    for ( int i = 1; i < first.size(); i++ ) {
                        firstTuple = new LeftTupleImpl( firstTuple,
                                                        new RightTuple( first.get( i )),
                                                        null,
                                                        false );
                    }

                    List<LeftTuple> leftTuples = new ArrayList<LeftTuple>();

                    for ( LeftTuple leftTuple = getFirst(memory.getLeftTupleMemory(), firstTuple); leftTuple != null; leftTuple = (LeftTuple) leftTuple.getNext() ) {
                        leftTuples.add( leftTuple );
                    }
                   
                    if ( lrUnlinkingEnabled ) {
                        // When L&R Unlinking is active, we need to sort the
                        // tuples here,
                        // because we might have asserted things in the wrong
                        // order,
                        // since linking a node's side means populating its
                        // memory
                        // from the OTN which stores things in a hash-set, so
                        // insertion order is not kept.
                        Collections.sort( leftTuples,
                                          new LeftTupleComparator() );

                    }
                   
                    List<List<InternalFactHandle>> actualLeftTuples = getHandlesList( leftTuples );


                    if ( !expectedLeftTuples.equals( actualLeftTuples ) ) {
                        throw new AssertionError( "line " + step.getLine() + ": left Memory expected " + expectedLeftTuples + " actually " + actualLeftTuples );
                    }

                } else if ( cmd[0].equals( "rightMemory" ) ) {
                    String args = cmd[1];
                    String listString = args.replaceAll( "h(\\d+)",
                                                         "h[$1]" );
                    Map<String, Object> vars = new HashMap<String, Object>();
                    vars.put( "h",
                              handles );
                    List< ? > expectedFactHandles = (List< ? >) MVEL.eval( listString,
                                                                           vars );

                    RightTupleMemory rightMemory = memory.getRightTupleMemory();

                    if ( expectedFactHandles.isEmpty() && rightMemory.size() != 0 ) {
                        throw new AssertionError( "line " + step.getLine() + ": right Memory expected [] actually " + print( rightMemory ));
                    } else if ( expectedFactHandles.isEmpty() && rightMemory.size() == 0 ) {
                        continue;
                    }

                    RightTuple first = new RightTuple( (InternalFactHandle) expectedFactHandles.get( 0 ) );
                    List<RightTuple> actualRightTuples = new ArrayList<RightTuple>();
                    for ( RightTuple rightTuple = getFirst(memory.getRightTupleMemory(), first); rightTuple != null; rightTuple = (RightTuple) rightTuple.getNext() ) {
                        actualRightTuples.add( rightTuple );
                    }

                    if ( expectedFactHandles.size() != actualRightTuples.size() ) {
                        throw new AssertionError( "line " + step.getLine() + ": right Memory expected " + print( expectedFactHandles )
                                                  + " actually " + print( actualRightTuples ));
                    }

                    for ( int i = 0, length = actualRightTuples.size(); i < length; i++ ) {
                        if ( expectedFactHandles.get( i ) != actualRightTuples.get( i ).getFactHandle() ) {
                            throw new AssertionError( "line " + step.getLine() + ": right Memory expected " + print( expectedFactHandles )
                                                      + " actually " + print( actualRightTuples ));
                        }
                    }

                } else {
                    throw new IllegalArgumentException( "line " + step.getLine() + ": command does not exist " + Arrays.toString( cmd ) );
                }
            }
        } catch ( Exception e ) {
            throw new IllegalArgumentException( "line " + step.getLine() + ": unable to execute step " + step,
                                                e );
        }
    }
   
    private LeftTuple getFirst(LeftTupleMemory memory, LeftTuple leftTuple) {
        Iterator it = memory.iterator();
        for ( LeftTuple next = ( LeftTuple ) it.next(); next != null; next = ( LeftTuple ) it.next() ) {
          if (next.equals( leftTuple ) ) {
              return next.getMemory().getFirst();
          }           
        }
       
        return null;
    }   
   
    private RightTuple  getFirst(RightTupleMemory memory, RightTuple rightTuple) {
        Iterator it = memory.iterator();
        for ( RightTuple next = (RightTuple) it.next( ); next != null; next = ( RightTuple ) it.next()) {
            if (next.equals( rightTuple ) ) {
                return next.getMemory().getFirst();
            }
        }
       
        return null;
    }

    private List<List<InternalFactHandle>> getHandlesList(
                                                          List<LeftTuple> leftTuples) {
        List<List<InternalFactHandle>> actualLeftTuples = new ArrayList<List<InternalFactHandle>>(
                                                                                                   leftTuples.size() );
        for ( LeftTuple leftTuple : leftTuples ) {
            List<InternalFactHandle> tupleHandles = Arrays.asList( leftTuple
                    .toFactHandles() );
            actualLeftTuples.add( tupleHandles );
        }
        return actualLeftTuples;
    }

    private String print(LeftTupleMemory leftMemory,
                         boolean lrUnlinkingEnabled) {

        List<LeftTuple> tuples = new ArrayList<LeftTuple>();
        Iterator it = leftMemory.iterator();
        for ( LeftTuple tuple = (LeftTuple) it.next(); tuple != null; tuple = (LeftTuple) it
                .next() ) {
            tuples.add( tuple );
        }

        if ( lrUnlinkingEnabled ) {
            // Necessary only when L&R unlinking are active.
            Collections.sort( tuples,
                              new LeftTupleComparator() );
        }

        return print( getHandlesList( tuples ) );
    }

    private String print(RightTupleMemory memory) {

        List<RightTuple> tuples = new ArrayList<RightTuple>();
        Iterator it = memory.iterator();

        for ( RightTuple tuple = (RightTuple) it.next(); tuple != null; tuple = (RightTuple) it
                .next() ) {
            tuples.add( tuple );
        }

        return "[" + print( tuples ) + "]";
    }

    /** Provides better error messages. */
    protected String print(List< ? > tuples) {

        StringBuilder b = new StringBuilder();

        for ( java.util.Iterator iterator = tuples.iterator(); iterator
                .hasNext(); ) {

            Object tuple = (Object) iterator.next();

            if ( tuple instanceof List< ? > ) {
                b.append( "[" );
                b.append( print( (List< ? >) tuple ) );
                b.append( "]" );
            } else if ( tuple instanceof InternalFactHandle ) {
                InternalFactHandle h = (InternalFactHandle) tuple;
                b.append( "h" ).append( h.getId() - 1 );
            } else if ( tuple instanceof RightTuple ) {
                InternalFactHandle h = (InternalFactHandle) ((RightTuple) tuple)
                        .getFactHandle();
                b.append( "h" ).append( h.getId() - 1 );
            }

            if ( iterator.hasNext() ) b.append( ", " );
        }

        if ( b.length() == 0 ) return "[]";

        return b.toString();
    }


    private void riaNode(DslStep step,
                         RightInputAdapterNode node,
                         Map<String, Object> context,
                         InternalWorkingMemory wm) {
        try {
            List<String[]> cmds = step.getCommands();
            List<InternalFactHandle> handles = (List<InternalFactHandle>) context.get( "Handles" );

            final ObjectHashMap memory = ((RiaNodeMemory) wm.getNodeMemory( node )).getMap();
            for ( String[] cmd : cmds ) {
                if ( cmd[0].equals( "leftMemory" ) ) {
                    String args = cmd[1];
                    String listString = args.replaceAll( "h(\\d+)",
                                                         "h[$1]" );
                    Map<String, Object> vars = new HashMap<String, Object>();
                    vars.put( "h",
                              handles );
                    List< ? > expectedLeftTuples = (List< ? >) MVEL.eval( listString,
                                                                          vars );

                    if ( expectedLeftTuples.isEmpty() && memory.size() != 0 ) {
                        throw new AssertionError( "line " + step.getLine() + ": left Memory expected [] actually " + memory );
                    } else if ( expectedLeftTuples.isEmpty() && memory.size() == 0 ) {
                        return;
                    }

                    // create expected tuples
                    List<LeftTuple> leftTuples = new ArrayList<LeftTuple>();
                    for ( List<InternalFactHandle> tlist : (List<List<InternalFactHandle>>) expectedLeftTuples ) {
                        LeftTuple tuple = new LeftTupleImpl( tlist.get( 0 ),
                                                         null,
                                                         false );
                        for ( int i = 1; i < tlist.size(); i++ ) {
                            tuple = new LeftTupleImpl( tuple,
                                                   new RightTuple( tlist.get( i ) ),
                                                   null,
                                                   false );
                        }
                        leftTuples.add( tuple );

                    }

                    // get actual tuples
                    final List<LeftTuple> actualTuples = new ArrayList<LeftTuple>();
                    final Iterator it = memory.iterator();
                    for ( ObjectEntry entry = (ObjectEntry) it.next(); entry != null; entry = (ObjectEntry) it.next() ) {
                        actualTuples.add( (LeftTuple) entry.getKey() );
                    }

                    // iterate over expected tuples and compare with actual tuples
                    for ( LeftTuple tuple : leftTuples ) {
                        if ( !actualTuples.remove( tuple ) ) {
                            throw new AssertionError( "line " + step.getLine() + ": left Memory expected " + tuple + " not found in memory." );
                        }
                    }
                    if ( !actualTuples.isEmpty() ) {
                        throw new AssertionError( "line " + step.getLine() + ": left Memory unexpected tuples in the node memory " + actualTuples );
                    }
                } else {
                    throw new IllegalArgumentException( "line " + step.getLine() + ": command does not exist " + Arrays.toString( cmd ) );
                }
            }
        } catch ( Exception e ) {
            throw new IllegalArgumentException( "line " + step.getLine() + ": unable to execute step " + step,
                                                e );
        }
    }

    private void ruleTerminalNode(DslStep step,
                                  RuleTerminalNode node,
                                  Map<String, Object> context,
                                  InternalWorkingMemory wm) {
        try {
            List<String[]> cmds = step.getCommands();
            //List<InternalFactHandle> handles = (List<InternalFactHandle>) context.get( "Handles" );

            for ( String[] cmd : cmds ) {
                throw new IllegalArgumentException( "line " + step.getLine() + ": command does not exist " + Arrays.toString( cmd ) );
            }
        } catch ( Exception e ) {
            throw new IllegalArgumentException( "line " + step.getLine() + ": unable to execute step " + step,
                                                e );
        }
    }

    @SuppressWarnings("unchecked")
    private void assertObject(DslStep step,
                              Map<String, Object> context,
                              InternalWorkingMemory wm) {
        try {
            List<String[]> cmds = step.getCommands();
            List<InternalFactHandle> handles = (List<InternalFactHandle>) context.get( "Handles" );
            for ( String[] cmd : cmds ) {
                try {
                    String nodeName = cmd[0];
                    Sink sink = (Sink) context.get( nodeName );
                    if ( sink == null ) {
                        throw new IllegalArgumentException( "line " + step.getLine() + ": node " + nodeName + " does not exist" );
                    }

                    Map<String, Object> vars = new HashMap<String, Object>();
                    vars.put( "h",
                              handles );
                    String args = cmd[1];
                    String listString = args.replaceAll( "h(\\d+)",
                                                         "h[$1]" );
                    List< ? > list = (List< ? >) MVEL.eval( listString,
                                                            vars );
                    if ( list == null ) {
                        throw new IllegalArgumentException( cmd + " does not specify an existing fact handle" );
                    }

                    for ( Object element : list ) {
                        if ( element == null ) {
                            throw new IllegalArgumentException( cmd + " does not specify an existing fact handle" );
                        }

                        if ( element instanceof InternalFactHandle ) {
                            InternalFactHandle handle = (InternalFactHandle) element;
                            PropagationContext pContext = new PropagationContextImpl( wm.getNextPropagationIdCounter(),
                                                                                      PropagationContext.INSERTION,
                                                                                      null,
                                                                                      null,
                                                                                      handle );
                            ((ObjectSink) sink).assertObject( handle,
                                                              pContext,
                                                              wm );
                            pContext.evaluateActionQueue( wm );
                        } else {
                            List<InternalFactHandle> tlist = (List<InternalFactHandle>) element;
                            LeftTuple tuple = createTuple( context,
                                                           tlist );
                            PropagationContext pContext = new PropagationContextImpl( wm.getNextPropagationIdCounter(),
                                                                                      PropagationContext.INSERTION,
                                                                                      null,
                                                                                      tuple,
                                                                                      null );
                            ((LeftTupleSink) sink).assertLeftTuple( tuple,
                                                                    pContext,
                                                                    wm );
                            pContext.evaluateActionQueue( wm );
                        }

                    }
                } catch ( Exception e ) {
                    throw new IllegalArgumentException( "line " + step.getLine() + ": unable to execute command " + cmd,
                                                        e );

                }
            }
        } catch ( Exception e ) {
            throw new IllegalArgumentException( "line " + step.getLine() + ": unable to execute step " + step,
                                                e );
        }
    }

    private LeftTuple createTuple(Map<String, Object> context,
                                  List<InternalFactHandle> tlist) {
        LeftTuple tuple = null;
        String id = getTupleId( tlist );
        for ( InternalFactHandle handle : tlist ) {
            if ( tuple == null ) {
                tuple = new LeftTupleImpl( handle,
                                           null,
                                           false ); // do not keep generated tuples on the handle list
            } else {
                tuple = new LeftTupleImpl( tuple,
                                           new RightTuple( handle ),
                                           null,
                                           true );
            }
        }
        context.put( id,
                     tuple );
        return tuple;
    }

    private String getTupleId(List<InternalFactHandle> tlist) {
        StringBuilder id = new StringBuilder();
        id.append( "T." );
        for ( InternalFactHandle handle : tlist ) {
            id.append( handle.getId() );
            id.append( "." );
        }
        return id.toString();
    }

    private void retractObject(DslStep step,
                               Map<String, Object> context,
                               InternalWorkingMemory wm) {
        try {
            List<String[]> cmds = step.getCommands();
            List<InternalFactHandle> handles = (List<InternalFactHandle>) context.get( "Handles" );
            for ( String[] cmd : cmds ) {
                try {
                    String nodeName = cmd[0];
                    Sink sink = (Sink) context.get( nodeName );
                    if ( sink == null ) {
                        throw new IllegalArgumentException( "line " + step.getLine() + ": node " + nodeName + " does not exist" );
                    }

                    String args = cmd[1];
                    String listString = args.replaceAll( "h(\\d+)",
                                                         "h[$1]" );
                    Map<String, Object> vars = new HashMap<String, Object>();
                    vars.put( "h",
                              handles );
                    List< ? > list = (List< ? >) MVEL.eval( listString,
                                                            vars );
                    if ( list == null ) {
                        throw new IllegalArgumentException( Arrays.toString( cmd ) + " does not specify an existing fact handle" );
                    }

                    for ( Object element : list ) {
                        if ( element == null ) {
                            throw new IllegalArgumentException( Arrays.toString( cmd ) + " does not specify an existing fact handle" );
                        }

                        if ( element instanceof InternalFactHandle ) {
                            InternalFactHandle handle = (InternalFactHandle) element;
                            PropagationContext pContext = new PropagationContextImpl( wm.getNextPropagationIdCounter(),
                                                                                      PropagationContext.DELETION,
                                                                                      null,
                                                                                      null,
                                                                                      handle );
                            if ( sink instanceof ObjectTypeNode ) {
                                ((ObjectTypeNode) sink).retractObject( handle,
                                                                       pContext,
                                                                       wm );
                            } else {
                                for ( RightTuple rightTuple = handle.getFirstRightTuple(); rightTuple != null; rightTuple = (RightTuple) rightTuple.getHandleNext() ) {
                                    rightTuple.getRightTupleSink().retractRightTuple( rightTuple,
                                                                                      pContext,
                                                                                      wm );
                                }
                                handle.clearRightTuples();
                                for ( LeftTuple leftTuple = handle.getFirstLeftTuple(); leftTuple != null; leftTuple = (LeftTuple) leftTuple.getLeftParentNext() ) {
                                    leftTuple.getLeftTupleSink().retractLeftTuple( leftTuple,
                                                                                   pContext,
                                                                                   wm );
                                }
                                handle.clearLeftTuples();
                            }
                            pContext.evaluateActionQueue( wm );
                        } else {
                            List<InternalFactHandle> tlist = (List<InternalFactHandle>) element;
                            String id = getTupleId( tlist );
                            LeftTuple tuple = (LeftTuple) context.remove( id );
                            if ( tuple == null ) {
                                throw new IllegalArgumentException( "Tuple not found: " + id + " : " + tlist.toString() );
                            }
                            PropagationContext pContext = new PropagationContextImpl( wm.getNextPropagationIdCounter(),
                                                                                      PropagationContext.DELETION,
                                                                                      null,
                                                                                      tuple,
                                                                                      null );
                            ((LeftTupleSink) sink).retractLeftTuple( tuple,
                                                                     pContext,
                                                                     wm );
                            pContext.evaluateActionQueue( wm );
                        }

                    }
                } catch ( Exception e ) {
                    throw new IllegalArgumentException( "line " + step.getLine() + ": unable to execute command " + Arrays.toString( cmd ),
                                                        e );

                }
            }
        } catch ( Exception e ) {
            throw new IllegalArgumentException( "line " + step.getLine() + ": unable to execute step " + step,
                                                e );
        }
    }

    private void modifyObject(DslStep step,
                              Map<String, Object> context,
                              InternalWorkingMemory wm) {
        try {
            List<String[]> cmds = step.getCommands();
            List<InternalFactHandle> handles = (List<InternalFactHandle>) context.get( "Handles" );
            for ( String[] cmd : cmds ) {
                try {
                    String nodeName = cmd[0];
                    Sink sink = (Sink) context.get( nodeName );
                    if ( sink == null ) {
                        throw new IllegalArgumentException( "line " + step.getLine() + ": node " + nodeName + " does not exist" );
                    }

                    String args = cmd[1];
                    String listString = args.replaceAll( "h(\\d+)",
                                                         "h[$1]" );
                    Map<String, Object> vars = new HashMap<String, Object>();
                    vars.put( "h",
                              handles );
                    List< ? > list = (List< ? >) MVEL.eval( listString,
                                                            vars );
                    if ( list == null ) {
                        throw new IllegalArgumentException( Arrays.toString( cmd ) + " does not specify an existing fact handle" );
                    }

                    for ( Object element : list ) {
                        if ( element == null ) {
                            throw new IllegalArgumentException( Arrays.toString( cmd ) + " does not specify an existing fact handle" );
                        }

                        if ( element instanceof InternalFactHandle ) {
                            InternalFactHandle handle = (InternalFactHandle) element;
                            PropagationContext pContext = new PropagationContextImpl( wm.getNextPropagationIdCounter(),
                                                                                      PropagationContext.MODIFICATION,
                                                                                      null,
                                                                                      null,
                                                                                      handle );
                            ModifyPreviousTuples modifyPreviousTuples = new ModifyPreviousTuples( handle.getFirstLeftTuple(),
                                                                                                  handle.getFirstRightTuple() );
                            handle.clearRightTuples();
                            handle.clearLeftTuples();
                            ((ObjectSink) sink).modifyObject( handle,
                                                              modifyPreviousTuples,
                                                              pContext,
                                                              wm );
                            modifyPreviousTuples.retractTuples( pContext,
                                                                wm );
                            pContext.evaluateActionQueue( wm );
                        } else {
                            List<InternalFactHandle> tlist = (List<InternalFactHandle>) element;
                            String id = getTupleId( tlist );
                            LeftTuple tuple = (LeftTuple) context.get( id );
                            if ( tuple == null ) {
                                throw new IllegalArgumentException( "Tuple not found: " + id + " : " + tlist.toString() );
                            }
                            PropagationContext pContext = new PropagationContextImpl( wm.getNextPropagationIdCounter(),
                                                                                      PropagationContext.MODIFICATION,
                                                                                      null,
                                                                                      tuple,
                                                                                      new DefaultFactHandle(1, "") );
                            ((LeftTupleSink) sink).modifyLeftTuple( tuple,
                                                                    pContext,
                                                                    wm );
                            pContext.evaluateActionQueue( wm );
                        }
                    }
                } catch ( Exception e ) {
                    throw new IllegalArgumentException( "line " + step.getLine() + ": unable to execute command " + cmd,
                                                        e );
                }
            }
        } catch ( Exception e ) {
            throw new IllegalArgumentException( "line " + step.getLine() + ": unable to execute step " + step,
                                                e );
        }
    }

    public static NodeTestCase compile(final Reader reader) throws IOException {
        NodeTestDSLParser parser = getParser( reader );
        return compile( parser );
    }

    public static NodeTestCase compile(final InputStream is) throws IOException {
        NodeTestDSLParser parser = getParser( is );
        return compile( parser );
    }

    public static NodeTestCase compile(final String source) throws IOException {
        NodeTestDSLParser parser = getParser( source );
        return compile( parser );
    }

    private static NodeTestCase compile(final NodeTestDSLParser parser) {
        try {
            compilation_unit_return cur = parser.compilation_unit();
            if ( parser.hasErrors() ) {
                NodeTestCase result = new NodeTestCase();
                result.setErrors( parser.getErrorMessages() );
                return result;
            }
            NodeTestCase testCase = walk( parser.getTokenStream(),
                                          (CommonTree) cur.getTree() );
            return testCase;
        } catch ( RecognitionException e ) {
            NodeTestCase result = new NodeTestCase();
            result.setErrors( Collections.singletonList( e.getMessage() ) );
            return result;
        }
    }

    private static NodeTestCase walk(TokenStream tokenStream,
                                     Tree resultTree) throws RecognitionException {
        CommonTreeNodeStream nodes = new CommonTreeNodeStream( resultTree );
        // AST nodes have payload that point into token stream
        nodes.setTokenStream( tokenStream );
        // Create a tree walker attached to the nodes stream
        NodeTestDSLTree walker = new NodeTestDSLTree( nodes );
        walker.compilation_unit();
        return walker.getTestCase();
    }

    private static NodeTestDSLParser getParser(final Reader reader) throws IOException {
        NodeTestDSLLexer lexer = new NodeTestDSLLexer( new ANTLRReaderStream( reader ) );
        NodeTestDSLParser parser = new NodeTestDSLParser( new CommonTokenStream( lexer ) );
        return parser;
    }

    private static NodeTestDSLParser getParser(final InputStream is) throws IOException {
        NodeTestDSLLexer lexer = new NodeTestDSLLexer( new ANTLRInputStream( is ) );
        NodeTestDSLParser parser = new NodeTestDSLParser( new CommonTokenStream( lexer ) );
        return parser;
    }

    private static NodeTestDSLParser getParser(final String source) throws IOException {
        NodeTestDSLLexer lexer = new NodeTestDSLLexer( new ANTLRStringStream( source ) );
        NodeTestDSLParser parser = new NodeTestDSLParser( new CommonTokenStream( lexer ) );
        return parser;
    }
   
    private static final class LeftTupleComparator implements Comparator<LeftTuple> {
       
        public int compare(LeftTuple o1,
                           LeftTuple o2) {

            InternalFactHandle[] h1 = o1.getFactHandles();
            InternalFactHandle[] h2 = o2.getFactHandles();

            // Handles have to be compared in the inverse order.
            for ( int i = (h1.length - 1); i >= 0; i-- ) {

                int diff = h1[i].getId() - h2[i].getId();

                // Will continue comparing handles until
                // a difference is found.
                if ( diff != 0 ) return diff;
            }

            return 0;
        }
    }

   

    public static class EmptyNotifier extends RunNotifier {
        public static final EmptyNotifier INSTANCE = new EmptyNotifier();

        @Override
        public void fireTestAssumptionFailed(Failure failure) {
        }

        @Override
        public void fireTestFailure(Failure failure) {
        }

        @Override
        public void fireTestFinished(Description description) {
        }

        @Override
        public void fireTestIgnored(Description description) {
        }

        @Override
        public void fireTestRunFinished(org.junit.runner.Result result) {
        }

        @Override
        public void fireTestRunStarted(Description description) {
        }

        @Override
        public void fireTestStarted(Description description) throws StoppedByUserException {
        }
    }
}
TOP

Related Classes of org.drools.reteoo.test.ReteDslTestEngine$LeftTupleComparator

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.