/*
* Copyright 2005 Red Hat, Inc. and/or its affiliates.
*
* 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.decisiontable.parser;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import java.util.Locale;
import org.drools.decisiontable.parser.xls.PropertiesSheetListener.CaseInsensitiveMap;
import org.drools.template.model.Condition;
import org.drools.template.model.Consequence;
import org.drools.template.model.DRLOutput;
import org.drools.template.model.Import;
import org.drools.template.model.Package;
import org.drools.template.model.Rule;
import org.drools.template.parser.DataListener;
import org.drools.template.parser.DecisionTableParseException;
import org.junit.Ignore;
import org.junit.Test;
import static org.junit.Assert.*;
/**
*
* Test an excel file.
*
* Assumes it has a sheet called "Decision Tables" with a rule table identified
* by a "RuleTable" cell
*/
public class RuleWorksheetParseTest {
@Test
public void testBasicWorkbookProperties() throws Exception {
final InputStream stream = RuleWorksheetParseTest.class.getResourceAsStream( "/data/BasicWorkbook.xls" );
final RuleSheetListener listener = getRuleSheetListener( stream );
final CaseInsensitiveMap props = listener.getProperties();
assertNotNull( props );
assertEquals( "myruleset", props.getSingleProperty( "RuleSet" ) );
assertEquals( "someMisc", props.getSingleProperty( "misc" ) );
/*
* System.out.println("Here are the global properties...");
* listener.getProperties().list(System.out);
*/
}
@Test
public void testComplexWorkbookProperties() throws Exception {
final InputStream stream = RuleWorksheetParseTest.class.getResourceAsStream( "/data/ComplexWorkbook.xls" );
final RuleSheetListener listener = getRuleSheetListener( stream );
final CaseInsensitiveMap props = listener.getProperties();
assertNotNull( props );
final String ruleSetName = props.getSingleProperty( "RuleSet" );
assertEquals( "ruleSetName", ruleSetName );
}
@Test
public void testWorkbookParse() throws Exception {
final InputStream stream = RuleWorksheetParseTest.class.getResourceAsStream( "/data/BasicWorkbook.xls" );
final RuleSheetListener listener = getRuleSheetListener( stream );
final Package ruleset = listener.getRuleSet();
assertNotNull( ruleset );
final Rule firstRule = (Rule) ruleset.getRules().get( 0 );
assertNotNull( firstRule.getSalience() );
assertTrue( Integer.parseInt( firstRule.getSalience() ) > 0 );
// System.out.println(ruleset.toXML());
assertEquals( "myruleset", ruleset.getName() );
assertEquals( 3, ruleset.getImports().size() );
assertEquals( 6, ruleset.getRules().size() );
// check imports
Import imp = (Import) ruleset.getImports().get( 0 );
assertEquals( "blah.class1", imp.getClassName() );
imp = (Import) ruleset.getImports().get( 1 );
assertEquals( "blah.class2", imp.getClassName() );
imp = (Import) ruleset.getImports().get( 2 );
assertEquals( "lah.di.dah", imp.getClassName() );
// check rules
Rule rule = (Rule) ruleset.getRules().get( 0 );
Condition cond = (Condition) rule.getConditions().get( 0 );
assertEquals( "Foo(myObject.getColour().equals(red), myObject.size () > 12\\\")",
cond.getSnippet() );
Consequence cons = (Consequence) rule.getConsequences().get( 0 );
assertNotNull( cons );
assertEquals( "myObject.setIsValid(Y);", cons.getSnippet() );
rule = (Rule) ruleset.getRules().get( 5 );
cond = (Condition) rule.getConditions().get( 1 );
assertEquals( "myObject.size () > 7", cond.getSnippet() );
cons = (Consequence) rule.getConsequences().get( 0 );
assertEquals( "myObject.setIsValid(10-Jul-1974)", cons.getSnippet() );
}
private RuleSheetListener listener;
private int row;
private void makeRuleSet(){
listener = new DefaultRuleSheetListener();
listener.startSheet( "bad_sheet" );
row = 1;
listener.newRow( row, 2 );
listener.newCell( row, 1, "RuleSet", DataListener.NON_MERGED );
listener.newCell( row, 2, "myRuleSet", DataListener.NON_MERGED );
}
private void makeAttribute( String key, String val){
row++;
listener.newRow( row, 2 );
listener.newCell( row, 1, key, DataListener.NON_MERGED );
listener.newCell( row, 2, val, DataListener.NON_MERGED );
}
private void makeRuleTable(){
listener.newRow( 10, 1 );
listener.newCell(10, 1, "RuleTable myRuleTable", DataListener.NON_MERGED );
}
private void makeRow( int row, String... values ) throws DecisionTableParseException {
listener.newRow( row, values.length );
for( int i = 0; i < values.length; i++ ){
if( values[i] != null ){
listener.newCell( row, i+1, values[i], DataListener.NON_MERGED );
}
}
}
/**
* Duplications of several columns are not permitted: NO-LOOP/U.
*/
@Test
public void testTooManyColumnsNoLoop() {
try {
makeRuleSet();
makeRuleTable();
makeRow( 11, "C", "C", "A", "U", "U" );
listener.finishSheet();
fail( "should have failed" );
} catch( DecisionTableParseException e ) {
String badCell = RuleSheetParserUtil.rc2name( 11, 5 );
System.err.println( e.getMessage() );
assertTrue( e.getMessage().contains( badCell ) );
}
}
/**
* Duplications of several columns are not permitted : PRIORITY/P.
*/
@Test
public void testTooManyColumnsPriority() {
try {
makeRuleSet();
makeRuleTable();
makeRow( 11, "C", "C", "A", "PRIORITY", "P" );
listener.finishSheet();
fail( "should have failed" );
} catch( DecisionTableParseException e ) {
String badCell = RuleSheetParserUtil.rc2name( 11, 5 );
System.err.println( e.getMessage() );
assertTrue( e.getMessage().contains( badCell ) );
}
}
/**
* Column headers must be valid.
*/
@Test
public void testBadColumnHeader() {
try {
makeRuleSet();
makeRuleTable();
makeRow( 11, "Condition", "CONDITION", "A", "SMURF", "P" );
listener.finishSheet();
fail( "should have failed" );
} catch( DecisionTableParseException e ) {
String badCell = RuleSheetParserUtil.rc2name( 11, 4 );
System.err.println( e.getMessage() );
assertTrue( e.getMessage().contains( badCell ) );
}
}
/**
* Must have a type for pattern below a condition, not a snippet.
*/
@Test
public void testMissingCondition() {
try {
makeRuleSet();
makeRuleTable();
makeRow( 11, "C", "C", "C", "A", "A" );
makeRow( 12, "attr == $param", "attr == $param", "attr == $param", "action();", "action();" );
listener.finishSheet();
fail( "should have failed" );
} catch( DecisionTableParseException e ) {
String badCell = RuleSheetParserUtil.rc2name( 12, 1 );
System.err.println( e.getMessage() );
assertTrue( e.getMessage().contains( badCell ) );
}
}
/**
* Must have a code snippet in a condition.
*/
@Test
public void testMissingCodeSnippetCondition() {
try {
makeRuleSet();
makeRuleTable();
makeRow( 11, "C", "C", "C", "A", "A" );
makeRow( 12, "Foo", "Foo", "Foo" );
makeRow( 13, "attr == $param", "attr == $param", "", "action();", "action();" );
makeRow( 15, "1", "2", "3", "", "" );
listener.finishSheet();
fail( "should have failed" );
} catch( DecisionTableParseException e ) {
String badCell = RuleSheetParserUtil.rc2name( 13, 3 );
System.err.println( e.getMessage() );
assertTrue( e.getMessage().contains( badCell ) );
}
}
/**
* Spurious code snippet.
*/
@Test
public void testSpuriousCodeSnippet() {
try {
makeRuleSet();
makeRuleTable();
makeRow( 11, "C", "C", "A" );
makeRow( 12, "Foo", "Foo" );
makeRow( 13, "attr == $param", "attr == $param", "action();", "attr > $param" );
makeRow( 15, "1", "2", "" );
listener.finishSheet();
fail( "should have failed" );
} catch( DecisionTableParseException e ) {
String badCell = RuleSheetParserUtil.rc2name( 13, 4 );
System.err.println( e.getMessage() );
assertTrue( e.getMessage().contains( badCell ) );
}
}
/**
* Incorrect priority - not numeric
*/
@Test
public void testIncorrectPriority() {
try {
makeRuleSet();
makeRuleTable();
makeRow( 11, "C", "A", "P" );
makeRow( 12, "Foo", "Foo" );
makeRow( 13, "attr == $param", "x" );
makeRow( 15, "1", "show()", "12E" );
listener.finishSheet();
fail( "should have failed" );
} catch( DecisionTableParseException e ) {
String badCell = RuleSheetParserUtil.rc2name( 15, 3 );
System.err.println( e.getMessage() );
assertTrue( e.getMessage().contains( badCell ) );
}
}
/**
* Must not have snippet for attribute
*/
@Test
public void testSnippetForAttribute() {
try {
makeRuleSet();
makeRuleTable();
makeRow( 11, "C", "A", "G" );
makeRow( 12, "Foo", "Foo" );
makeRow( 13, "attr == $param", "x", "XXX" );
makeRow( 15, "1", "show()", "10" );
listener.finishSheet();
fail( "should have failed" );
} catch( DecisionTableParseException e ) {
String badCell = RuleSheetParserUtil.rc2name( 13, 3 );
System.err.println( e.getMessage() );
assertTrue( e.getMessage().contains( badCell ) );
}
}
/**
* Check correct rendering of string-valued attribute
*/
@Test
public void testRuleAttributeRendering() {
makeRuleSet();
makeRuleTable();
makeRow( 11, "C", "A", "G" );
makeRow( 12, "Foo", "Foo" );
makeRow( 13, "attr == $param", "x" );
makeRow( 15, "1", "show()", "foo bar" );
makeRow( 16, "2", "list()", "\"10\" group\"" );
listener.finishSheet();
Package p = listener.getRuleSet();
DRLOutput dout = new DRLOutput();
p.renderDRL(dout);
String drl = dout.getDRL();
// System.out.println( drl );
assertTrue( drl.contains( "agenda-group \"foo bar\"" ) );
assertTrue( drl.contains( "agenda-group \"10\\\" group\"" ) );
}
/**
* Duplicate package level attribute
*/
@Test
public void testDuplicatePackageAttribute() {
try {
makeRuleSet();
makeAttribute( "agenda-group", "agroup" ); // B3, C3
makeAttribute( "agenda-group", "bgroup" ); // B3. B4
makeRuleTable();
makeRow( 11, "C", "A", "P" );
makeRow( 12, "Foo", "Foo" );
makeRow( 13, "attr == $param", "x" );
makeRow( 15, "1", "show()", "10" );
listener.finishSheet();
Package p = listener.getRuleSet();
DRLOutput dout = new DRLOutput();
p.renderDRL(dout);
String drl = dout.getDRL();
// System.out.println( drl );
fail( "should have failed" );
} catch( DecisionTableParseException e ) {
System.err.println( e.getMessage() );
assertTrue( e.getMessage().contains( "C3, C4" ) );
}
}
/**
* Check correct rendering of package level attributes
*/
@Test
public void testPackageAttributeRendering() {
makeRuleSet();
makeAttribute( "NO-LOOP", "true" );
makeAttribute( "agenda-group", "agroup" );
makeRuleTable();
makeRow( 11, "C", "A", "P" );
makeRow( 12, "foo:Foo", "foo" );
makeRow( 13, "attr == $param", "x($param)" );
makeRow( 15, "1", "1", "100" );
listener.finishSheet();
Package p = listener.getRuleSet();
DRLOutput dout = new DRLOutput();
p.renderDRL(dout);
String drl = dout.getDRL();
// System.out.println( drl );
assertTrue( drl.contains( "no-loop true" ) );
assertTrue( drl.contains( "agenda-group \"agroup\"" ) );
}
/**
* Must have a code snippet in an action.
*/
@Test
public void testMissingCodeSnippetAction() {
try {
makeRuleSet();
makeRuleTable();
makeRow( 11, "C", "A" );
makeRow( 12, "foo: Foo", "Bar()" );
makeRow( 13, "attr == $param" );
makeRow( 15, "1", "1" );
makeRow( 16, "2", "2" );
listener.finishSheet();
Package p = listener.getRuleSet();
DRLOutput dout = new DRLOutput();
p.renderDRL(dout);
String drl = dout.getDRL();
System.out.println( drl );
fail( "should have failed" );
} catch( DecisionTableParseException e ) {
String badCell = RuleSheetParserUtil.rc2name( 13, 2 );
System.err.println( e.getMessage() );
assertTrue( e.getMessage().contains( badCell ) );
}
}
@Test
public void testMetadata() {
makeRuleSet();
makeRuleTable();
makeRow( 11, "C", "A", "@", "@" );
makeRow( 12, "foo: Foo", "foo" );
makeRow( 13, "attr == $param", "goaway($param)", "Author($param)", "Version($1-$2)" );
makeRow( 15, "1", "1", "J.W.Goethe", "3,14" );
makeRow( 16, "2", "2", "", "" );
listener.finishSheet();
Package p = listener.getRuleSet();
DRLOutput dout = new DRLOutput();
p.renderDRL(dout);
String drl = dout.getDRL();
assertTrue( drl.contains( "@Author(J.W.Goethe)" ) );
assertTrue( drl.contains( "@Version(3-14)" ) );
assertFalse( drl.contains( "@Author()" ) );
assertFalse( drl.contains( "@Version(-)" ) );
}
@Test
public void testQuoteEscapingEnabled() throws Exception {
final InputStream stream = RuleWorksheetParseTest.class.getResourceAsStream( "/data/QuoteEscapeEnabledWorkbook.xls" );
final RuleSheetListener listener = getRuleSheetListener( stream );
final Package ruleset = listener.getRuleSet();
assertNotNull( ruleset );
DRLOutput dout = new DRLOutput();
ruleset.renderDRL(dout);
String drl = dout.getDRL();
System.out.println(drl);
// check rules
Rule rule = ruleset.getRules().get( 0 );
Condition cond = rule.getConditions().get( 0 );
assertEquals( "Foo(myObject.getColour().equals(red), myObject.size () > 12\\\")",
cond.getSnippet() );
}
@Test
public void testQuoteEscapingDisabled() throws Exception {
final InputStream stream = RuleWorksheetParseTest.class.getResourceAsStream( "/data/QuoteEscapeDisabledWorkbook.xls" );
final RuleSheetListener listener = getRuleSheetListener( stream );
final Package ruleset = listener.getRuleSet();
assertNotNull( ruleset );
DRLOutput dout = new DRLOutput();
ruleset.renderDRL(dout);
String drl = dout.getDRL();
System.out.println(drl);
// check rules
Rule rule = (Rule) ruleset.getRules().get( 0 );
Condition cond = (Condition) rule.getConditions().get( 0 );
assertEquals( "Foo(myObject.getColour().equals(red), myObject.size () > \"12\")",
cond.getSnippet() );
rule = ruleset.getRules().get( 1 );
cond = rule.getConditions().get( 0 );
assertEquals( "Foo(myObject.getColour().equals(blue), myObject.size () > 12\")",
cond.getSnippet() );
}
@Test
public void testSalienceRange() throws Exception {
// DROOLS-1225
final InputStream stream = RuleWorksheetParseTest.class.getResourceAsStream( "/data/SalienceRangeWorkbook.xls" );
final RuleSheetListener listener = getRuleSheetListener( stream );
final Package ruleset = listener.getRuleSet();
assertNotNull( ruleset );
DRLOutput dout = new DRLOutput();
ruleset.renderDRL(dout);
String drl = dout.getDRL();
System.out.println(drl);
// check rules
List<Rule> rules = ruleset.getRules();
assertEquals( "10000",
rules.get(0).getSalience() );
assertEquals( "9999",
rules.get(1).getSalience() );
}
@Test
public void testSalienceOutOfRange() throws Exception {
// DROOLS-1225
final InputStream stream = RuleWorksheetParseTest.class.getResourceAsStream( "/data/SalienceOutOfRangeWorkbook.xls" );
try {
final RuleSheetListener listener = getRuleSheetListener( stream );
fail( "should have failed" );
} catch (DecisionTableParseException e) { }
}
/**
* See if it can cope with odd shaped rule table, including missing
* conditions. Also is not "sequential".
*/
@Test
public void testComplexWorksheetMissingConditionsInLocaleEnUs() throws Exception {
Locale originalDefaultLocale = Locale.getDefault();
Locale.setDefault(Locale.US);
doComplexWorksheetMissingConditions();
Locale.setDefault(originalDefaultLocale);
}
@Test @Ignore // TODO JBRULES-2880 TIRELLI: Ignore test while we decide what to do in order to solve i18n issues
public void testComplexWorksheetMissingConditionsInLocaleFrFr() throws Exception {
Locale originalDefaultLocale = Locale.getDefault();
Locale.setDefault(Locale.FRANCE);
doComplexWorksheetMissingConditions();
Locale.setDefault(originalDefaultLocale);
}
private void doComplexWorksheetMissingConditions() throws IOException {
final InputStream stream = RuleWorksheetParseTest.class.getResourceAsStream( "/data/ComplexWorkbook.xls" );
final RuleSheetListener listener = getRuleSheetListener( stream );
final Package ruleset = listener.getRuleSet();
assertEquals( 6, ruleset.getRules().size() );
assertEquals( 0, ruleset.getImports().size() );
Rule rule = (Rule) ruleset.getRules().get( 0 );
assertEquals( 3, rule.getConditions().size() );
assertEquals( 2, rule.getConsequences().size() );
final Consequence cons = (Consequence) rule.getConsequences().get( 1 );
assertEquals( "myObject.setIsValid(1, 2)", cons.getSnippet() );
final Condition con = (Condition) rule.getConditions().get( 2 );
assertEquals( "myObject.size() < $3.00", con.getSnippet() );
rule = (Rule) ruleset.getRules().get( 4 );
// this should have less conditions
assertEquals( 1, rule.getConditions().size() );
rule = (Rule) ruleset.getRules().get( 5 );
assertEquals( 2, rule.getConditions().size() );
assertEquals( 1, rule.getConsequences().size() );
}
@Test
public void testNumericDisabled() throws Exception {
// DROOLS-1378
final InputStream stream = RuleWorksheetParseTest.class.getResourceAsStream( "/data/NumericDisabled.xls" );
final RuleSheetListener listener = getRuleSheetListener( stream );
final Package ruleset = listener.getRuleSet();
assertNotNull( ruleset );
DRLOutput dout = new DRLOutput();
ruleset.renderDRL( dout );
String drl = dout.getDRL();
System.out.println( drl );
// check rules
Rule rule = (Rule) ruleset.getRules().get( 0 );
Condition cond = (Condition) rule.getConditions().get( 0 );
assertEquals( "Cheese(price == 6600)", cond.getSnippet() );
}
/**
* Utility method showing how to get a rule sheet listener from a stream.
*/
public static RuleSheetListener getRuleSheetListener(final InputStream stream) throws IOException {
return RulesheetUtil.getRuleSheetListener( stream );
}
}