/** * 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.clips; import java.io.InputStream; import java.io.InputStreamReader; import java.io.Reader; import java.util.List; import java.util.Map; import junit.framework.TestCase; import org.antlr.runtime.ANTLRStringStream; import org.antlr.runtime.CharStream; import org.antlr.runtime.CommonTokenStream; import org.drools.lang.descr.AndDescr; import org.drools.lang.descr.AttributeDescr; import org.drools.lang.descr.EvalDescr; import org.drools.lang.descr.ExistsDescr; import org.drools.lang.descr.FieldBindingDescr; import org.drools.lang.descr.FieldConstraintDescr; import org.drools.lang.descr.LiteralRestrictionDescr; import org.drools.lang.descr.NotDescr; import org.drools.lang.descr.OrDescr; import org.drools.lang.descr.PatternDescr; import org.drools.lang.descr.PredicateDescr; import org.drools.lang.descr.RestrictionConnectiveDescr; import org.drools.lang.descr.ReturnValueRestrictionDescr; import org.drools.lang.descr.RuleDescr; public class LhsClpParserTest extends TestCase { private ClipsParser parser; //XFunctionRegistry registry; public void setUp() { //this.registry = new XFunctionRegistry( BuiltinFunctions.getInstance() ); } protected void tearDown() throws Exception { super.tearDown(); //this.parser = null; } public void testParseFunction() throws Exception { // BuildContext context = new ExecutionBuildContext( new CLPPredicate(), this.registry ); // FunctionCaller fc = ( FunctionCaller ) parse( "(< 1 2)" ).lisp_list( context, new LispForm2(context) ); // // assertEquals( "<", fc.getName() ); // assertEquals( new LongValueHandler( 1 ), fc.getParameters()[0] ); // assertEquals( new LongValueHandler( 2 ), fc.getParameters()[1] ); } public void testPatternsRule() throws Exception { // the first pattern bellowshould generate a descriptor tree like that: // Pattern[person] // | // AND // / \ // FB FC[person name] // | // OR // +----------|------------+ // LR LR AND // / \ // RVR PC // MARK: is it valid to add a predicate restriction as part of a field constraint? I mean, shouldn't // the predicate be out of the (name ...) scope? RuleDescr rule = parse( "(defrule xxx ?b <- (person (name \"yyy\"&?bf|~\"zzz\"|~=(+ 2 3)&:(< 1 2)) ) ?c <- (hobby (type ?bf2&~iii) (rating fivestar) ) => )" ).defrule(); assertEquals( "xxx", rule.getName() ); AndDescr lhs = rule.getLhs(); List lhsList = lhs.getDescrs(); assertEquals( 2, lhsList.size() ); // Parse the first pattern PatternDescr personPattern = (PatternDescr) lhsList.get( 0 ); assertEquals( "$b", personPattern.getIdentifier() ); assertEquals( "person", personPattern.getObjectType() ); List colList = personPattern.getDescrs(); assertEquals( 3, colList.size() ); // first, we have a field binding FieldBindingDescr fbd = (FieldBindingDescr) colList.get( 0 ); assertEquals( "$bf", fbd.getIdentifier() ); assertEquals( "name", fbd.getFieldName() ); // then, we have a field constraint FieldConstraintDescr fieldConstraintDescr = (FieldConstraintDescr) colList.get( 1 ); assertEquals( "name", fieldConstraintDescr.getFieldName() ); RestrictionConnectiveDescr root = (RestrictionConnectiveDescr) fieldConstraintDescr.getRestriction(); assertEquals( 1, root.getRestrictions().size() ); RestrictionConnectiveDescr or = (RestrictionConnectiveDescr) root.getRestrictions().get( 0 ); assertEquals( RestrictionConnectiveDescr.OR, or.getConnective() ); List restrictionList = or.getRestrictions(); assertEquals( 3, restrictionList.size() ); // first we have a literal restriction LiteralRestrictionDescr litDescr = (LiteralRestrictionDescr) restrictionList.get( 0 ); assertEquals( "==", litDescr.getEvaluator() ); assertEquals( "yyy", litDescr.getText() ); // second, we have another literal restriction litDescr = (LiteralRestrictionDescr) restrictionList.get( 1 ); assertEquals( "!=", litDescr.getEvaluator() ); assertEquals( "zzz", litDescr.getText() ); ReturnValueRestrictionDescr retDescr = (ReturnValueRestrictionDescr) restrictionList.get( 2 ); assertEquals( "!=", retDescr.getEvaluator() ); LispForm lispForm = ( LispForm ) retDescr.getContent(); assertEquals("(+ 2 3)", lispForm.toString() ); // ---------------- // this is how it would be compatible to our core engine PredicateDescr predicateDescr = (PredicateDescr) colList.get( 2 ); lispForm = ( LispForm ) predicateDescr.getContent(); assertEquals("(< 1 2)", lispForm.toString() ); // ----------------- // Parse the second column PatternDescr hobbyPattern = (PatternDescr) lhsList.get( 1 ); assertEquals( "$c", hobbyPattern.getIdentifier() ); assertEquals( "hobby", hobbyPattern.getObjectType() ); colList = hobbyPattern.getDescrs(); assertEquals( 3, colList.size() ); fbd = (FieldBindingDescr) colList.get( 0 ); assertEquals( "$bf2", fbd.getIdentifier() ); assertEquals( "type", fbd.getFieldName() ); fieldConstraintDescr = (FieldConstraintDescr) colList.get( 1 ); restrictionList = fieldConstraintDescr.getRestrictions(); assertEquals( "type", fieldConstraintDescr.getFieldName() ); assertEquals( RestrictionConnectiveDescr.AND, fieldConstraintDescr.getRestriction().getConnective() ); litDescr = (LiteralRestrictionDescr) restrictionList.get( 0 ); assertEquals( "!=", litDescr.getEvaluator() ); assertEquals( "iii", litDescr.getText() ); fieldConstraintDescr = (FieldConstraintDescr) colList.get( 2 ); restrictionList = fieldConstraintDescr.getRestrictions(); assertEquals( "rating", fieldConstraintDescr.getFieldName() ); litDescr = (LiteralRestrictionDescr) restrictionList.get( 0 ); assertEquals( "==", litDescr.getEvaluator() ); assertEquals( "fivestar", litDescr.getText() ); } public void testNestedCERule() throws Exception { RuleDescr rule = parse( "(defrule xxx ?b <- (person (name yyy)) (or (and (hobby1 (type qqq1)) (hobby2 (type ~qqq2))) (food (veg ~shroom) ) ) => )" ).defrule(); assertEquals( "xxx", rule.getName() ); AndDescr lhs = rule.getLhs(); List lhsList = lhs.getDescrs(); assertEquals( 2, lhsList.size() ); // Parse the first column PatternDescr col = (PatternDescr) lhsList.get( 0 ); assertEquals( "$b", col.getIdentifier() ); assertEquals( "person", col.getObjectType() ); FieldConstraintDescr fieldConstraintDescr = (FieldConstraintDescr) col.getDescrs().get( 0 ); assertEquals( "name", fieldConstraintDescr.getFieldName() ); // LiteralRestrictionDescr litDescr = (LiteralRestrictionDescr) fieldConstraintDescr.getRestrictions().get( 0 ); assertEquals( "==", litDescr.getEvaluator() ); assertEquals( "yyy", litDescr.getText() ); OrDescr orDescr = (OrDescr) lhsList.get( 1 ); assertEquals( 2, orDescr.getDescrs().size() ); AndDescr andDescr = (AndDescr) orDescr.getDescrs().get( 0 ); col = (PatternDescr) andDescr.getDescrs().get( 0 ); assertEquals( "hobby1", col.getObjectType() ); fieldConstraintDescr = (FieldConstraintDescr) col.getDescrs().get( 0 ); assertEquals( "type", fieldConstraintDescr.getFieldName() ); // litDescr = (LiteralRestrictionDescr) fieldConstraintDescr.getRestrictions().get( 0 ); assertEquals( "==", litDescr.getEvaluator() ); assertEquals( "qqq1", litDescr.getText() ); col = (PatternDescr) andDescr.getDescrs().get( 1 ); assertEquals( "hobby2", col.getObjectType() ); fieldConstraintDescr = (FieldConstraintDescr) col.getDescrs().get( 0 ); assertEquals( "type", fieldConstraintDescr.getFieldName() ); // litDescr = (LiteralRestrictionDescr) fieldConstraintDescr.getRestrictions().get( 0 ); assertEquals( "!=", litDescr.getEvaluator() ); assertEquals( "qqq2", litDescr.getText() ); col = (PatternDescr) orDescr.getDescrs().get( 1 ); assertEquals( "food", col.getObjectType() ); fieldConstraintDescr = (FieldConstraintDescr) col.getDescrs().get( 0 ); assertEquals( "veg", fieldConstraintDescr.getFieldName() ); // litDescr = (LiteralRestrictionDescr) fieldConstraintDescr.getRestrictions().get( 0 ); assertEquals( "!=", litDescr.getEvaluator() ); assertEquals( "shroom", litDescr.getText() ); } public void testNotExistsRule() throws Exception { RuleDescr rule = parse( "(defrule xxx (or (hobby1 (type qqq1)) (not (and (exists (person (name ppp))) (person (name yyy))))) => )" ).defrule(); assertEquals( "xxx", rule.getName() ); AndDescr lhs = rule.getLhs(); List lhsList = lhs.getDescrs(); assertEquals( 1, lhsList.size() ); OrDescr orDescr = (OrDescr) lhsList.get( 0 ); assertEquals( 2, orDescr.getDescrs().size() ); PatternDescr col = (PatternDescr) orDescr.getDescrs().get( 0 ); assertEquals( "hobby1", col.getObjectType() ); FieldConstraintDescr fieldConstraintDescr = (FieldConstraintDescr) col.getDescrs().get( 0 ); assertEquals( "type", fieldConstraintDescr.getFieldName() ); // LiteralRestrictionDescr litDescr = (LiteralRestrictionDescr) fieldConstraintDescr.getRestrictions().get( 0 ); assertEquals( "==", litDescr.getEvaluator() ); assertEquals( "qqq1", litDescr.getText() ); NotDescr notDescr = (NotDescr) orDescr.getDescrs().get( 1 ); assertEquals( 1, notDescr.getDescrs().size() ); AndDescr andDescr = (AndDescr) notDescr.getDescrs().get( 0 ); assertEquals( 2, andDescr.getDescrs().size() ); ExistsDescr existsDescr = (ExistsDescr) andDescr.getDescrs().get( 0 ); col = (PatternDescr) existsDescr.getDescrs().get( 0 ); assertEquals( "person", col.getObjectType() ); fieldConstraintDescr = (FieldConstraintDescr) col.getDescrs().get( 0 ); assertEquals( "name", fieldConstraintDescr.getFieldName() ); // litDescr = (LiteralRestrictionDescr) fieldConstraintDescr.getRestrictions().get( 0 ); assertEquals( "==", litDescr.getEvaluator() ); assertEquals( "ppp", litDescr.getText() ); col = (PatternDescr) andDescr.getDescrs().get( 1 ); assertEquals( "person", col.getObjectType() ); fieldConstraintDescr = (FieldConstraintDescr) col.getDescrs().get( 0 ); assertEquals( "name", fieldConstraintDescr.getFieldName() ); // litDescr = (LiteralRestrictionDescr) fieldConstraintDescr.getRestrictions().get( 0 ); assertEquals( "==", litDescr.getEvaluator() ); assertEquals( "yyy", litDescr.getText() ); } public void testTestRule() throws Exception { RuleDescr rule = parse( "(defrule xxx (test (< 9.0 1.3) ) => )" ).defrule(); assertEquals( "xxx", rule.getName() ); AndDescr lhs = rule.getLhs(); List lhsList = lhs.getDescrs(); assertEquals( 1, lhsList.size() ); EvalDescr evalDescr = (EvalDescr) lhsList.get( 0 ); LispForm lispForm = ( LispForm ) evalDescr.getContent(); assertEquals("(< 9.0 1.3)", lispForm.toString() ); } public void testRuleHeader() throws Exception { RuleDescr rule = parse( "(defrule MAIN::name \"docs\"(declare (salience -100) ) => )" ).defrule(); Map<String, AttributeDescr> attributes = rule.getAttributes(); AttributeDescr module = ( AttributeDescr ) attributes.get( "agenda-group" ); assertEquals( "agenda-group", module.getName() ); assertEquals( "MAIN", module.getValue() ); assertEquals("name", rule.getName() ); AttributeDescr dialect = ( AttributeDescr ) attributes.get( "dialect" ); assertEquals( "dialect", dialect.getName() ); assertEquals( "clips", dialect.getValue() ); AttributeDescr salience = ( AttributeDescr ) attributes.get( "salience" ); assertEquals( "salience", salience.getName() ); assertEquals( "-100", salience.getValue() ); } private ClipsParser parse(final String text) throws Exception { return new ClipsParser( new CommonTokenStream( new ClipsLexer( new ANTLRStringStream( text ) ) ) ); } private ClipsParser parse(final String source, final String text) throws Exception { this.parser = new ClipsParser( new CommonTokenStream( new ClipsLexer( new ANTLRStringStream( text ) ) ) ); this.parser.setSource( source ); return this.parser; } private Reader getReader(final String name) throws Exception { final InputStream in = getClass().getResourceAsStream( name ); return new InputStreamReader( in ); } private ClipsParser parseResource(final String name) throws Exception { Reader reader = getReader( name ); final StringBuffer text = new StringBuffer(); final char[] buf = new char[1024]; int len = 0; while ( (len = reader.read( buf )) >= 0 ) { text.append( buf, 0, len ); } return parse( name, text.toString() ); } private CharStream newCharStream(final String text) { return new ANTLRStringStream( text ); } private void assertEqualsIgnoreWhitespace(final String expected, final String actual) { final String cleanExpected = expected.replaceAll( "\\s+", "" ); final String cleanActual = actual.replaceAll( "\\s+", "" ); assertEquals( cleanExpected, cleanActual ); } }