package detective.core.runner; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Set; import org.hamcrest.Matcher; import org.junit.Assert; import com.google.common.base.Optional; import com.google.common.collect.ImmutableList; import detective.core.Detective; import detective.core.Parameters; import detective.core.Scenario; import detective.core.Story; import detective.core.TestTask; import detective.core.dsl.DslException; import detective.core.dsl.ParametersImpl; import detective.core.dsl.builder.DslBuilder; import detective.core.dsl.table.Row; import detective.core.dsl.table.TableParser; import detective.utils.Utils; import geb.Browser; import groovy.lang.Closure; import groovy.lang.GroovyObject; import groovy.lang.GroovyObjectSupport; import groovy.lang.GroovyRuntimeException; import groovy.util.Expando; /** * Delegate for expect closure. * <pre> then "I should have four black sweaters in stock"{ sweater.balck << equalTo(4) } * </pre> * <br> * The operation << leftShift will actually runs the code, but which code * will run will delegate out. * <br> * @author James Luo * */ public class ExpectClosureDelegate extends PropertyToStringDelegate{ /** * Create a new ROOT expect closure delegate * */ public ExpectClosureDelegate(Parameters values){ super(values); } /** * * @param parent can not be null */ public ExpectClosureDelegate(PropertyToStringDelegate parent, String propertyName, Parameters values){ super(parent, propertyName, values); } public void leftShift(Object obj){ //Invoked here? user must typed the property wrong, we throw exception and tell user what's the problem property throw new WrongPropertyNameInDslException(this.getFullPropertyName()); } public Object getProperty(String property){ if ("browser".equals(property)) return this.browser(); Object result = super.getProperty(property); if (! (result instanceof PropertyToStringDelegate)){ return new ExpectObjectWrapperWrapper(result); }else return result; } protected PropertyToStringDelegate newNextLevelProperty(PropertyToStringDelegate parent, String propertyName){ return new ExpectClosureDelegate(parent, propertyName, values); } public void runtask(Object obj){ throw new DslException("implement interface TestTask and your class is " + obj.getClass().getName()); } public void runtask(TestTask task){ Parameters datain = this.getValues(); Parameters dataReturned = task.execute(datain); this.getValues().putAllUnwrappered(dataReturned); } public void logMessage(Object msg){ Object realMsg = Utils.getRealValue(msg); if (realMsg instanceof List || realMsg instanceof Map) Detective.logUserMessageAsTable(this.getValues(), "", msg); else Detective.logUserMessage(this.getValues(), msg.toString()); } public void runtask(Map<?, ?> parameters, TestTask task){ for (Object key : parameters.keySet()){ if (key != null) this.getValues().put(key.toString(), parameters.get(key)); } this.runtask(task); } public void runtask(List<?> tasks){ for (Object item : tasks){ if (item instanceof TestTask){ runtask((TestTask)item); } } } public Browser browser(){ return Detective.newBrowser(); } public void browser(Closure<?> closure){ Detective._browser(Detective.newBrowser(), closure); } public List<Row> table(Closure<?> closure){ return TableParser.asListOfRows(values, closure); } public void expect(String errorMsg, Closure<?> closure){ List<String> list = new ArrayList<String>(); list.add(errorMsg); expect(list, closure); } private void errorMsgContains(String errorMsg, Throwable e) throws AssertionError { if (e.getMessage() == null && errorMsg == null) return; if (e.getMessage() == null && errorMsg != null) throw new AssertionError("Get a null error message but expect " + errorMsg); if (e.getMessage() != null){ if (!e.getMessage().contains(errorMsg)){ throw new AssertionError("\nExpected: " + errorMsg + "\n got:" + e.getMessage()); } } } public void expect(List<String> errorMsgs, Closure<?> closure){ try { closure.setDelegate(this); closure.setResolveStrategy(Closure.DELEGATE_FIRST); closure.call(); } catch (Throwable e) { for (String errorMsg : errorMsgs) errorMsgContains(errorMsg, e); } } public Object invokeMethod(String name, Object args) { return super.invokeMethod(name, args); } }