/*
* Copyright 2015 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.
*
* 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.compiler.lang.dsl;
import java.io.IOException;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.List;
import org.drools.compiler.lang.dsl.DSLMappingEntry;
import org.drools.compiler.lang.dsl.DSLTokenizedMappingFile;
import org.drools.compiler.lang.dsl.DefaultDSLMapping;
import org.drools.compiler.lang.dsl.DefaultExpander;
import org.junit.Test;
import static org.junit.Assert.*;
public class DSLMappingEntryTest {
// Due to a bug in JDK 5, a workaround for zero-width lookbehind has to be used.
// JDK works correctly with "(?<=^|\\W)"
private static final String lookbehind = "(?:(?<=^)|(?<=\\W))";
private static final String NL = System.getProperty("line.separator");
private DSLMappingEntry createEntry(final String inputKey,
final String inputValue) throws IOException {
String mapping = "[condition][]" + inputKey + "=" + inputValue;
StringReader dsl = new StringReader( mapping );
DSLMappingEntry entry = null;
try {
DSLTokenizedMappingFile parser = new DSLTokenizedMappingFile();
if ( parser.parseAndLoad( dsl ) ) {
entry = parser.getMapping().getEntries().get( 0 );
} else {
throw new RuntimeException( "Error parsing entry: " + mapping + ": " + parser.getErrors().toString() );
}
} finally {
dsl.close();
}
return entry;
}
@Test
public void testPatternCalculation() throws IOException {
final String inputKey = "The Customer name is {name} and surname is {surname} and it has US$ 50,00 on his {pocket}";
final String inputValue = "Customer( name == \"{name}\", surname == \"{surname}\", money > $money )";
final String expectedKeyP = lookbehind + "The\\s+Customer\\s+name\\s+is\\s+(.*?)\\s+and\\s+surname\\s+is\\s+(.*?)\\s+and\\s+it\\s+has\\s+US\\$\\s+50,00\\s+on\\s+his\\s+(.*?)$";
final String expectedValP = "Customer( name == \"{name}\", surname == \"{surname}\", money > $money )";
final DSLMappingEntry entry = createEntry( inputKey,
inputValue );
assertEquals( inputKey,
entry.getMappingKey() );
assertEquals( expectedKeyP,
entry.getKeyPattern().pattern() );
assertEquals( inputValue,
entry.getMappingValue() );
assertEquals( expectedValP,
entry.getValuePattern() );
}
@Test
public void testPatternCalculation2() throws IOException {
final String inputKey = "-name is {name}";
final String inputValue = "name == \"{name}\"";
final String expectedKeyP = lookbehind + "-\\s*name\\s+is\\s+(.*?)$";
final String expectedValP = "name == \"{name}\"";
final DSLMappingEntry entry = createEntry( inputKey,
inputValue );
assertEquals( inputKey,
entry.getMappingKey() );
assertEquals( expectedKeyP,
entry.getKeyPattern().pattern() );
assertEquals( inputValue,
entry.getMappingValue() );
assertEquals( expectedValP,
entry.getValuePattern() );
}
@Test
public void testPatternCalculation3() throws IOException {
final String inputKey = "- name is {name}";
final String inputValue = "name == \"{name}\"";
final String expectedKeyP = lookbehind + "-\\s*name\\s+is\\s+(.*?)$";
final String expectedValP = "name == \"{name}\"";
final DSLMappingEntry entry = createEntry( inputKey,
inputValue );
assertEquals( inputKey,
entry.getMappingKey() );
assertEquals( entry.getKeyPattern().pattern(),
expectedKeyP,
entry.getKeyPattern().pattern() );
assertEquals( inputValue,
entry.getMappingValue() );
assertEquals( expectedValP,
entry.getValuePattern() );
}
private DSLMappingEntry setupEntry() throws IOException {
final String inputKey = "String is \"{value}\"";
final String inputValue = "SomeFact(value==\"{value}\")";
return createEntry( inputKey,
inputValue );
}
private DefaultExpander makeExpander( DSLMappingEntry... entries ){
DefaultExpander expander = new DefaultExpander();
DefaultDSLMapping mapping = new DefaultDSLMapping();
for( DSLMappingEntry entry: entries ){
mapping.addEntry( entry );
}
List<String> options = new ArrayList<String>();
options.add("result");
options.add("when");
options.add("steps");
mapping.setOptions(options);
expander.addDSLMapping(mapping);
return expander;
}
@Test
public void testExpandSpaces() throws IOException {
DSLMappingEntry entry = this.setupEntry();
DefaultExpander ex = makeExpander( entry );
String[] strs = new String[]{ "0_sp", " 1_sp", " 3_sp", "0_sp_1 ",
"0_sp_3 ", "0_sp 1_sp 2_sp", " 3_sp 3_sp 1_sp 1_sp_2 " };
StringBuilder sb = new StringBuilder( "rule x\n" + "when\n" );
for( String str: strs ){
sb.append( "String is \"" + str + "\"" + NL );
}
sb.append( "then\n" + "end\n" );
String dslr = sb.toString();
String drl = ex.expand( dslr );
for( String str: strs ){
assertTrue( drl.contains( '"' + str + '"' ) );
}
}
@Test
public void testExpandWithDots() throws IOException {
DSLMappingEntry entry1 = this.createEntry( "- {prop} is not {val} ", "{prop} != {val}" );
DSLMappingEntry entry2 = this.createEntry( "- {prop} is {val} ", "{prop} == {val}" );
DSLMappingEntry entry3 = this.createEntry( "- {prop} is_not {val} ", "{prop} != {val}" );
DefaultExpander ex = makeExpander( entry1, entry2, entry3 );
StringBuilder sb = new StringBuilder( "rule x\n" ).append( "when\n" );
sb.append( "> Foo()").append( NL );
sb.append( "- type1 is ClientServiceType.TypeGOLD" ).append( NL );
sb.append( "- type2 is_not ClientServiceType.TypeGOLD" ).append( NL );
sb.append( "- type3 is not ClientServiceType.TypeGOLD" ).append( NL );
sb.append( "then\n" ).append( "end\n" );
String dslr = sb.toString();
String drl = ex.expand( dslr );
System.out.println( dslr );
System.out.println( drl );
assertTrue( "failure type1", drl.contains( "type1 == ClientServiceType.TypeGOLD" ) );
assertTrue( "failure type2", drl.contains( "type2 != ClientServiceType.TypeGOLD" ) );
assertTrue( "failure type3", drl.contains( "type3 != ClientServiceType.TypeGOLD" ) );
}
@Test
public void testExpandWithBrackets() throws IOException {
DSLMappingEntry entry1 = this.createEntry( "attr {attr_name} is in \\[ {values} \\]",
"{attr_name} in ( {values} )" );
DSLMappingEntry entry2 = this.createEntry( "((H|h)e|(S|s)he) \\(is\\) (a|an) $xx {attribute} (man|woman)",
"Person( attribute == \"{attribute}\" )" );
DSLMappingEntry entry3 = this.createEntry( "DSL sentence with {key1} {key2}",
"Sentence( {key1} == {key2} )" );
DSLMappingEntry entry4 = this.createEntry( "When the credit rating is {rating:ENUM:Applicant.creditRating}",
"applicant:Applicant(credit=={rating})" );
DSLMappingEntry entry5 = this.createEntry( "When the credit rating is {rating:regex:\\d{3}}",
"applicant:Applicant(credit=={rating})" );
assertEquals( lookbehind + "When\\s+the\\s+credit\\s+rating\\s+is\\s+(\\d{3})(?=\\W|$)",
entry5.getKeyPattern().toString() );
assertEquals( "applicant:Applicant(credit=={rating})",
entry5.getValuePattern() );
DSLMappingEntry entry6 = this.createEntry( "This is a sentence with line breaks",
"Cheese\\n(price == 10)" );
assertEquals( lookbehind + "This\\s+is\\s+a\\s+sentence\\s+with\\s+line\\s+breaks(?=\\W|$)",
entry6.getKeyPattern().toString() );
assertEquals( "Cheese\n(price == 10)",
entry6.getValuePattern());
DSLMappingEntry entry7 = this.createEntry( "Bedingung-\\#19-MKM4",
"eval ( $p.getTempVal(\"\\#UML-ATZ-1\") < $p.getZvUmlStfr() )" );
assertEquals( lookbehind + "Bedingung-#19-MKM4(?=\\W|$)",
entry7.getKeyPattern().toString() );
assertEquals( "eval ( $p.getTempVal(\"#UML-ATZ-1\") < $p.getZvUmlStfr() )",
entry7.getValuePattern());
DefaultExpander ex = makeExpander( entry1, entry2, entry3, entry4,
entry5, entry6, entry7 );
StringBuilder sb = new StringBuilder( "rule x\n" ).append( "when\n" );
sb.append( "attr name is in [ 'Edson', 'Bob' ]" ).append( NL );
sb.append( "he (is) a $xx handsome man" ).append( NL );
sb.append( "DSL sentence with mykey myvalue" ).append( NL );
sb.append( "When the credit rating is AA" ).append( NL );
sb.append( "When the credit rating is 555" ).append( NL );
sb.append( "This is a sentence with line breaks" ).append( NL );
sb.append( "Bedingung-#19-MKM4" ).append( NL );
sb.append( "then\n" + "end\n" );
String dslr = sb.toString();
String drl = ex.expand( dslr );
for( String exp: new String[]{
"name in ( 'Edson', 'Bob' )",
"Person( attribute == \"handsome\" )",
"Sentence( mykey == myvalue )",
// "applicant:Applicant(credit==AA)",
"applicant:Applicant(credit==555)",
"Cheese\n(price == 10)",
"eval ( $p.getTempVal(\"#UML-ATZ-1\") < $p.getZvUmlStfr() )" } ){
assertTrue( "failed to expand to: " + exp, drl.contains( exp ) );
}
}
@Test
public void testCreateWithTilde() throws IOException {
//If the statement parses it passes. To test expressions in dsl with a ~
try{
DSLMappingEntry entry1 = this.createEntry( "the benefit HAS an EXACT message of {ALLMSG}",
"$benefit :Map(this['ALLMSG'] matches \"(?i).*~{ALLMSG}~.*\") from $benefits");
}catch(Exception e){
fail(e.getMessage());
}
}
}