/**
* 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.ide.common.client.modeldriven.testing;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.drools.ide.common.client.modeldriven.brl.PortableObject;
/**
* This represents a test scenario.
* It also encapsulates the result of a scenario run.
*
* @author Michael Neale
*/
public class Scenario
implements
PortableObject {
/**
* The maximum number of rules to fire so we don't recurse for ever.
*/
public int maxRuleFirings = 100000;
/**
* global data which must be setup before hand.
*/
public List<FactData> globals = new ArrayList<FactData>();
/**
* Fixtures are parts of the test. They may be assertions, globals, data, execution runs etc.
* Anything really.
*
*/
public List<Fixture> fixtures = new ArrayList<Fixture>();
/**
* This is the date the last time the scenario was run (and what the results apply to).
*/
public Date lastRunResult;
/**
* the rules to include or exclude
*/
public List<String> rules = new ArrayList<String>();
/**
* true if only the rules in the list should be allowed to fire. Otherwise
* it is exclusive (ie all rules can fire BUT the ones in the list).
*/
public boolean inclusive = false;
/**
* Returns true if this was a totally successful scenario, based on the results contained.
*/
public boolean wasSuccessful() {
for ( Iterator iterator = fixtures.iterator(); iterator.hasNext(); ) {
Fixture f = (Fixture) iterator.next();
if ( f instanceof Expectation ) {
if ( !((Expectation) f).wasSuccessful() ) {
return false;
}
}
}
return true;
}
/**
* Will slip in a fixture after the specified one, but before the next execution trace.
*/
public void insertBetween(Fixture fix,
Fixture toAdd) {
boolean inserted = false;
int start = (fix == null) ? 0 : fixtures.indexOf( fix ) + 1;
for ( int j = start; j < fixtures.size(); j++ ) {
Fixture f = (Fixture) fixtures.get( j );
if ( f instanceof ExecutionTrace ) {
fixtures.add( j,
toAdd );
System.out.println(toAdd.toString());
return;
}
}
if ( !inserted ) {
//fixtures.add( fixtures.indexOf(fix) + 1, toAdd);
fixtures.add( toAdd );
}
}
/**
* Remove the specified fixture.
*/
public void removeFixture(Fixture f) {
this.fixtures.remove( f );
this.globals.remove( f );
}
/**
* Remove fixtures between this ExecutionTrace and the previous one.
*/
public void removeExecutionTrace(ExecutionTrace et) {
boolean remove = false;
for ( Iterator<Fixture> iterator = fixtures.iterator(); iterator.hasNext(); ) {
Fixture f = iterator.next();
if ( f.equals( et ) ) {
remove = true;
continue;
} else if ( remove && (f instanceof ExecutionTrace || (f instanceof FactData)) ) {
break;
}
if ( remove ) {
iterator.remove();
this.globals.remove( f );
}
}
Collections.reverse( fixtures );
remove = false;
for ( Iterator<Fixture> iterator = fixtures.iterator(); iterator.hasNext(); ) {
Fixture f = iterator.next();
// Catch the first or next ExecutionTrace.
if ( f.equals( et ) ) {
remove = true;
} else if ( remove && (f instanceof ExecutionTrace || (f instanceof VerifyFact)) ) {
break;
}
if ( remove ) {
iterator.remove();
this.globals.remove( f );
}
}
Collections.reverse( fixtures );
}
/**
*
* @return A mapping of variable names to their fact type.
*/
public Map getFactTypes() {
Map m = new HashMap();
int p = this.fixtures.size();
for ( int i = 0; i < p; i++ ) {
Fixture f = (Fixture) fixtures.get( i );
if ( f instanceof FactData ) {
FactData fd = (FactData) f;
m.put( fd.name,
fd );
}
}
return m;
}
/**
*
* @return A mapping of variable names to their fact type.
*/
public Map<String, String> getVariableTypes() {
Map<String, String> map = new HashMap<String, String>();
for ( Fixture fixture : fixtures ) {
if ( fixture instanceof FactData ) {
FactData factData = (FactData) fixture;
map.put( factData.name,
factData.type );
}
}
for ( FactData factData : globals ) {
map.put( factData.name,
factData.type );
}
return map;
}
/**
* This will return a list of fact names that are in scope (including globals).
* @return List<String>
*/
public List<String> getFactNamesInScope(ExecutionTrace ex,
boolean includeGlobals) {
if ( ex == null ) return Collections.emptyList();
List<String> factDataNames = new ArrayList<String>();
int p = this.fixtures.indexOf( ex );
for ( int i = 0; i < p; i++ ) {
Fixture fixture = (Fixture) fixtures.get( i );
if ( fixture instanceof FactData ) {
FactData factData = (FactData) fixture;
factDataNames.add( factData.name );
} else if ( fixture instanceof RetractFact ) {
RetractFact retractFact = (RetractFact) fixture;
factDataNames.remove( retractFact.name );
}
}
if ( includeGlobals ) {
for ( FactData factData : globals ) {
factDataNames.add( factData.name );
}
}
return factDataNames;
}
/**
* @return true iff a fact name is already in use.
*/
public boolean isFactNameExisting(String factName) {
for ( Iterator iterator = globals.iterator(); iterator.hasNext(); ) {
FactData fd = (FactData) iterator.next();
if ( fd.name.equals( factName ) ) {
return true;
}
}
for ( Iterator iterator = fixtures.iterator(); iterator.hasNext(); ) {
Fixture f = (Fixture) iterator.next();
if ( f instanceof FactData ) {
FactData fd = (FactData) f;
if ( fd.name.equals( factName ) ) {
return true;
}
}
}
return false;
}
/**
* @return true iff a fact is actually used (ie if its not, its safe to remove it).
*/
public boolean isFactNameUsed(FactData fd) {
int start = this.fixtures.indexOf( fd );
for ( int i = start + 1; i < fixtures.size(); i++ ) {
Fixture f = (Fixture) fixtures.get( i );
if ( f instanceof RetractFact ) {
if ( ((RetractFact) f).name.equals( fd.name ) ) {
return true;
}
} else if ( f instanceof VerifyFact ) {
if ( ((VerifyFact) f).name.equals( fd.name ) ) {
return true;
}
} else if ( f instanceof FactData ) {
if ( ((FactData) f).name.equals( fd.name ) ) {
return true;
}
}
}
return false;
}
/**
*
* @return int[0] = failures, int[1] = total;
*/
public int[] countFailuresTotal() {
int total = 0;
int failures = 0;
for ( Iterator iterator = fixtures.iterator(); iterator.hasNext(); ) {
Fixture f = (Fixture) iterator.next();
if ( f instanceof VerifyRuleFired ) {
total++;
VerifyRuleFired vr = (VerifyRuleFired) f;
if ( vr.successResult != null && !vr.successResult.booleanValue() ) {
failures++;
}
} else if ( f instanceof VerifyFact ) {
VerifyFact vf = (VerifyFact) f;
for ( Iterator it = vf.fieldValues.iterator(); it.hasNext(); ) {
VerifyField vfl = (VerifyField) it.next();
if ( vfl.successResult != null && !vfl.successResult.booleanValue() ) {
failures++;
}
total++;
}
}
}
return new int[]{failures, total};
}
public String printFailureReport() {
int total = 0;
int failures = 0;
StringBuilder buf = new StringBuilder();
buf.append( "------- Unmet expectations: -------\n" );
for ( Iterator iterator = fixtures.iterator(); iterator.hasNext(); ) {
Fixture f = (Fixture) iterator.next();
if ( f instanceof VerifyRuleFired ) {
total++;
VerifyRuleFired vr = (VerifyRuleFired) f;
if ( vr.successResult != null && !vr.successResult.booleanValue() ) {
failures++;
buf.append( vr.explanation );
buf.append( '\n' );
}
} else if ( f instanceof VerifyFact ) {
VerifyFact vf = (VerifyFact) f;
for ( Iterator it = vf.fieldValues.iterator(); it.hasNext(); ) {
VerifyField vfl = (VerifyField) it.next();
if ( vfl.successResult != null && !vfl.successResult.booleanValue() ) {
failures++;
buf.append( vfl.explanation );
buf.append( '\n' );
}
total++;
}
}
}
buf.append( "\n------- Summary: ------\n" );
buf.append( failures + " failures out of " + total + " expectations." );
return buf.toString();
}
}