/** * 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.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; 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.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.BetaMemory; import org.drools.reteoo.BetaNode; import org.drools.reteoo.LeftTuple; 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.RightTuple; import org.drools.reteoo.RightTupleMemory; import org.drools.reteoo.RuleTerminalNode; import org.drools.reteoo.Sink; import org.drools.reteoo.AccumulateNode.AccumulateMemory; 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.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.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.dsl.NodeTestCaseResult.NodeTestResult; import org.drools.reteoo.test.dsl.NodeTestCaseResult.Result; import org.drools.reteoo.test.parser.NodeTestDSLLexer; import org.drools.reteoo.test.parser.NodeTestDSLParser; import org.drools.reteoo.test.parser.NodeTestDSLTree; import org.drools.reteoo.test.parser.NodeTestDSLParser.compilation_unit_return; 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 { 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( 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 = 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; } result.add( testResult ); } return result; } private NodeTestResult run(NodeTestCase testCase, NodeTestDef test) { Map<String, Object> context = createContext( testCase ); NodeTestResult result = new NodeTestResult( test, Result.NOT_EXECUTED, context, new LinkedList<String>() ); 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 ( Exception e ) { result.result = Result.ERROR; result.errorMsgs.add( e.getMessage() ); } 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() ); context.put( "BuildContext", buildContext ); context.put( "ClassFieldAccessorStore", this.reteTesterHelper.getStore() ); InternalWorkingMemory wm = (InternalWorkingMemory) rbase.newStatefulSession( true ); context.put( "WorkingMemory", wm ); return context; } public Map<String, Object> run(Map<String, Object> context, List<DslStep> steps, NodeTestResult result) { InternalWorkingMemory wm = (InternalWorkingMemory) context.get( "WorkingMemory" ); 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) { 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 AssertionError( "line " + step.getLine() + ": left Memory expected [] actually " + leftMemory ); } else if ( expectedLeftTuples.isEmpty() && leftMemory.size() == 0 ) { return; } // we always lookup from the first element, in case it's indexed List<InternalFactHandle> first = (List<InternalFactHandle>) expectedLeftTuples.get( 0 ); LeftTuple firstTuple = new LeftTuple( first.get( 0 ), null, false ); for ( int i = 1; i < first.size(); i++ ) { firstTuple = new LeftTuple( firstTuple, null, false ); } List<LeftTuple> leftTuples = new ArrayList<LeftTuple>(); for ( LeftTuple leftTuple = memory.getLeftTupleMemory().getFirst( firstTuple ); leftTuple != null; leftTuple = (LeftTuple) leftTuple.getNext() ) { leftTuples.add( leftTuple ); } List<List<InternalFactHandle>> actualLeftTuples = new ArrayList<List<InternalFactHandle>>( leftTuples.size() ); for ( LeftTuple leftTuple : leftTuples ) { List<InternalFactHandle> tupleHandles = Arrays.asList( leftTuple.toFactHandles() ); actualLeftTuples.add( tupleHandles ); } 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 " + rightMemory ); } else if ( expectedFactHandles.isEmpty() && rightMemory.size() == 0 ) { return; } RightTuple first = new RightTuple( (InternalFactHandle) expectedFactHandles.get( 0 ) ); List<RightTuple> actualRightTuples = new ArrayList<RightTuple>(); for ( RightTuple rightTuple = memory.getRightTupleMemory().getFirst( first ); rightTuple != null; rightTuple = (RightTuple) rightTuple.getNext() ) { actualRightTuples.add( rightTuple ); } if ( expectedFactHandles.size() != actualRightTuples.size() ) { throw new AssertionError( "line " + step.getLine() + ": right Memory expected " + expectedFactHandles + " actually " + 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 " + expectedFactHandles + " actually " + 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 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 = (ObjectHashMap) 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 ); 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 LeftTuple( tlist.get( 0 ), null, false ); for ( int i = 1; i < tlist.size(); i++ ) { tuple = new LeftTuple( 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.ASSERTION, null, null, handle ); ((ObjectSink) sink).assertObject( handle, pContext, wm ); } else { List<InternalFactHandle> tlist = (List<InternalFactHandle>) element; LeftTuple tuple = createTuple( context, tlist ); PropagationContext pContext = new PropagationContextImpl( wm.getNextPropagationIdCounter(), PropagationContext.ASSERTION, null, tuple, null ); ((LeftTupleSink) sink).assertLeftTuple( tuple, pContext, 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 LeftTuple( handle, null, false ); // do not keep generated tuples on the handle list } else { tuple = new LeftTuple( 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.RETRACTION, 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.setFirstRightTuple( null ); handle.setLastRightTuple( null ); for ( LeftTuple leftTuple = handle.getFirstLeftTuple(); leftTuple != null; leftTuple = (LeftTuple) leftTuple.getLeftParentNext() ) { leftTuple.getLeftTupleSink().retractLeftTuple( leftTuple, pContext, wm ); } handle.setFirstLeftTuple( null ); handle.setLastLeftTuple( null ); } } 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.RETRACTION, null, tuple, null ); ((LeftTupleSink) sink).retractLeftTuple( tuple, pContext, 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.setFirstLeftTuple( null ); handle.setFirstRightTuple( null ); handle.setLastLeftTuple( null ); handle.setLastRightTuple( null ); ((ObjectSink) sink).modifyObject( handle, modifyPreviousTuples, pContext, wm ); modifyPreviousTuples.retractTuples( pContext, 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, null ); ((LeftTupleSink) sink).modifyLeftTuple( tuple, pContext, 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; } 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 { } } }