package detective.core.dsl.builder; import groovy.lang.Closure; import groovy.util.BuilderSupport; import groovy.util.Expando; import java.util.HashMap; import java.util.List; import java.util.Map; import org.codehaus.groovy.runtime.InvokerHelper; import detective.core.Parameters; import detective.core.Scenario; import detective.core.Story; import detective.core.dsl.DslException; import detective.core.dsl.ParametersImpl; import detective.core.dsl.SimpleScenario; import detective.core.dsl.SimpleStep; import detective.core.dsl.SimpleStory; import detective.core.dsl.table.Row; @SuppressWarnings("rawtypes") public class DslBuilder extends BuilderSupport{ private Map<SimpleScenario, Parameters> scenariosParameters = new HashMap<SimpleScenario, Parameters>(); private Parameters getParametersFromScenario(SimpleScenario s){ Parameters parameters = scenariosParameters.get(s); if (parameters == null){ parameters = new ParametersImpl(s.getStory().getSharedDataMap()); scenariosParameters.put(s, parameters); } return scenariosParameters.get(s); } public static final String DATATABLE_PARAMNAME = "datatable"; public static DslBuilder story(){ return new DslBuilder(); } protected Object doInvokeMethod(String methodName, Object name, Object args) { Object current = getCurrent(); if (current != null){ List list = InvokerHelper.asList(args); if (list.size() == 1 && list.get(0) instanceof Closure){ Closure closure = (Closure)list.get(0); if (current instanceof Scenario){ if (methodName.equalsIgnoreCase("scenarioTable")){ //scenario table ScenarioTable table = new ScenarioTable((Scenario)current); List<Row> rows = table.scenarioTable(closure); List<Row> existsRows = ((Scenario)current).getScenarioTable(); existsRows.clear(); existsRows.addAll(rows); return rows; }else{ ScenarioDelegate sub = new ScenarioDelegate(getParametersFromScenario((SimpleScenario)current)); sub.setScenario((SimpleScenario)current); sub.setTitle(name.toString()); sub.setClosure(closure); SimpleStep outcomes = new SimpleStep(); outcomes.setTitle(sub.title); outcomes.setExpectClosure(sub.closure); sub.scenario.addStep(outcomes); return sub; } }else if (current instanceof Story && (methodName.equalsIgnoreCase("share"))){ StoryDelegate sub = new StoryDelegate(new ParametersImpl()); sub.story = (Story)current; sub.closure = closure; closure.setDelegate(sub); closure.setResolveStrategy(Closure.DELEGATE_ONLY); closure.call(); addStorySharedData(sub, (Story)current, null); return current; } } } return super.doInvokeMethod(methodName, name, args); } @Override protected Object createNode(Object name) { Object current = getCurrent(); if (current == null){ SimpleStory story = new SimpleStory(); story.setTitle(name.toString()); return story; }else if (current instanceof Story){ SimpleStory story = (SimpleStory)current; SimpleScenario s = new SimpleScenario(story, name.toString()); story.getScenarios().add(s); return s; }else if (current instanceof Scenario){ throw new DslException("Should never reach here."); }else if (current instanceof ScenarioDelegate){ return new Expando(); } return null; } @Override protected Object createNode(Object name, Object value) { if (value instanceof SimpleScenario){ SimpleScenario s = (SimpleScenario)value; s.setId(name.toString()); return value; }else if (value instanceof ScenarioDelegate){ ScenarioDelegate sub = (ScenarioDelegate)value; // if (name.toString().equalsIgnoreCase("given") || name.toString().equalsIgnoreCase("when")){ // SimpleContext context = null; // if (name.toString().equalsIgnoreCase("given")){ // context = new SimpleContext(sub.getScenario()); // sub.getScenario().addContext(context); // }else // context = (SimpleEvents)sub.scenario.getEvents(); // // context.setTitle(sub.title); // if (sub.closure != null){ // sub.closure.setResolveStrategy(Closure.DELEGATE_ONLY); // sub.closure.setDelegate(sub); // try { // sub.closure.call(); // }catch (DslException e1) { // throw e1; // } catch (Exception e) { // throw new DslException(e.getMessage() + ". Please note we have a know ambiguousness for parent child relationship, for example login.username is a valid identifier for us, but when you add login.username.lastname, we have no idea it is going to access a property from identifier login.username or it is a new identifier.", e); // } // } // addContextParameters(sub, context, null); // }else if (name.toString().equalsIgnoreCase("when")){ // SimpleEvents events = (SimpleEvents)sub.scenario.getEvents(); // events.setTitle(sub.title); // }else if (name.toString().equalsIgnoreCase("then")) { //SimpleOutcomes outcomes = (SimpleOutcomes)sub.scenario.getOutcomes(); } return sub.scenario; }else if (getCurrent() == null){ SimpleStory story = new SimpleStory(); return story; }else if (getCurrent() instanceof Story){ SimpleStory story = (SimpleStory)getCurrent(); if (name.toString().equalsIgnoreCase("sothat")) story.setPurpose(value.toString()); else if (name.toString().equalsIgnoreCase("asa")) story.setRole(value.toString()); else if (name.toString().equalsIgnoreCase("inorderto")){ story.setFeature(value.toString()); }else if (name.toString().equalsIgnoreCase("iwantto")) story.setBenefit(value.toString()); return story; } return null; } private void addStorySharedData(StoryDelegate sub, Story story, String propertyPrix) { if (sub.getProperties().size() == 0) story.putSharedData(sub.getFullPropertyName(), null); for (Object k : sub.getProperties().keySet()){ String key = k.toString(); Object value = sub.getProperty(key); if (value instanceof StoryDelegate){ this.addStorySharedData((StoryDelegate)value, story, (propertyPrix == null ? "" : propertyPrix + ".") + key); }else{ story.putSharedData((propertyPrix == null ? "" : propertyPrix + ".") + key, value); } } } @Override protected Object createNode(Object name, Map attributes) { throw new DslException("Unsupported DSL Format : " + name); } @Override protected Object createNode(Object name, Map attributes, Object value) { throw new DslException("Unsupported DSL Format : " + name); } @Override protected void setParent(Object parent, Object child) { } }