- Revision
- 755
- Author
- mauro
- Date
- 2007-07-11 17:10:48 -0500 (Wed, 11 Jul 2007)
Log Message
JBEHAVE-94: Added velocity-based code generator.
Modified Paths
Added Paths
- trunk/core/src/behaviour/org/jbehave/core/story/codegen/velocity/
- trunk/core/src/behaviour/org/jbehave/core/story/codegen/velocity/VelocityCodeGeneratorBehaviour.java
- trunk/core/src/java/org/jbehave/core/story/codegen/velocity/
- trunk/core/src/java/org/jbehave/core/story/codegen/velocity/VelocityCodeGenerator.java
- trunk/core/src/java/org/jbehave/core/story/codegen/velocity/templates/
- trunk/core/src/java/org/jbehave/core/story/codegen/velocity/templates/event.template
- trunk/core/src/java/org/jbehave/core/story/codegen/velocity/templates/given.template
- trunk/core/src/java/org/jbehave/core/story/codegen/velocity/templates/outcome.template
Diff
Modified: trunk/core/src/behaviour/org/jbehave/core/story/AllBehaviours.java (754 => 755)
--- trunk/core/src/behaviour/org/jbehave/core/story/AllBehaviours.java 2007-07-11 20:07:29 UTC (rev 754) +++ trunk/core/src/behaviour/org/jbehave/core/story/AllBehaviours.java 2007-07-11 22:10:48 UTC (rev 755) @@ -9,6 +9,7 @@ import org.jbehave.core.behaviour.Behaviours; import org.jbehave.core.story.codegen.parser.TextStoryParserBehaviour; +import org.jbehave.core.story.codegen.velocity.VelocityCodeGeneratorBehaviour; import org.jbehave.core.story.domain.AbstractStepBehaviour; import org.jbehave.core.story.domain.GivenScenarioBehaviour; import org.jbehave.core.story.domain.GivenStepBehaviour; @@ -41,6 +42,7 @@ AbstractStepBehaviour.class, PlainTextScenarioListenerBehaviour.class, PlainTextRendererBehaviour.class, + VelocityCodeGeneratorBehaviour.class }; } }
Added: trunk/core/src/behaviour/org/jbehave/core/story/codegen/velocity/VelocityCodeGeneratorBehaviour.java (0 => 755)
--- trunk/core/src/behaviour/org/jbehave/core/story/codegen/velocity/VelocityCodeGeneratorBehaviour.java (rev 0) +++ trunk/core/src/behaviour/org/jbehave/core/story/codegen/velocity/VelocityCodeGeneratorBehaviour.java 2007-07-11 22:10:48 UTC (rev 755) @@ -0,0 +1,60 @@ +package org.jbehave.core.story.codegen.velocity; + +import java.io.File; + +import org.jbehave.core.mock.UsingMatchers; +import org.jbehave.core.story.codegen.domain.ScenarioDetails; +import org.jbehave.core.story.codegen.domain.StoryDetails; + +/** + * + * @author Mauro Talevi + */ +public class VelocityCodeGeneratorBehaviour extends UsingMatchers { + + public void shouldGenerateCodeForStoryWithFullScenario() throws Exception { + // given + StoryDetails storyDetails = new StoryDetails("Joe drinks vodka", "", "", ""); + ScenarioDetails scenario1 = new ScenarioDetails(); + scenario1.name = "Happy path"; + scenario1.context.givens.add("a bar downtown"); + scenario1.context.givens.add("a thirsty Joe"); + scenario1.event.name = "Joe asks for a Smirnov"; + scenario1.outcome.outcomes.add("bartender serves Joe"); + scenario1.outcome.outcomes.add("Joe is happy"); + storyDetails.addScenario(scenario1); + ScenarioDetails scenario2 = new ScenarioDetails(); + scenario2.name = "Unhappy path"; + scenario2.context.givens.add("a pub uptown"); + scenario2.context.givens.add("an equally thirsty Joe"); + scenario2.event.name = "Joe asks for an Absolut"; + scenario2.outcome.outcomes.add("bartender tells Joe it is sold out"); + scenario2.outcome.outcomes.add("Joe is unhappy"); + storyDetails.addScenario(scenario2); + + // when + String generatedSourceDir = "delete_me/generated-src"; + VelocityCodeGenerator generator = new VelocityCodeGenerator(generatedSourceDir, + "generated.stories"); + generator.generateStory(storyDetails); + + // then + String[] generatedPaths = new String[]{ + "events/JoeAsksForASmirnov.java", + "events/JoeAsksForAnAbsolut.java", + "givens/ABarDowntown.java", + "givens/APubUptown.java", + "givens/AThirstyJoe.java", + "givens/AnEquallyThirstyJoe.java", + "outcomes/BartenderServesJoe.java", + "outcomes/BartenderTellsJoeItIsSoldOut.java", + "outcomes/JoeIsHappy.java", + "outcomes/JoeIsUnhappy.java" + }; + + for ( int i = 0; i < generatedPaths.length; i++ ){ + ensureThat(new File(generatedSourceDir+File.separator+generatedPaths[i]).exists() ); + } + } + +}
Added: trunk/core/src/java/org/jbehave/core/story/codegen/velocity/VelocityCodeGenerator.java (0 => 755)
--- trunk/core/src/java/org/jbehave/core/story/codegen/velocity/VelocityCodeGenerator.java (rev 0) +++ trunk/core/src/java/org/jbehave/core/story/codegen/velocity/VelocityCodeGenerator.java 2007-07-11 22:10:48 UTC (rev 755) @@ -0,0 +1,124 @@ +package org.jbehave.core.story.codegen.velocity; + +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.io.Writer; +import java.text.MessageFormat; +import java.util.Iterator; +import java.util.Properties; + +import org.apache.velocity.Template; +import org.apache.velocity.VelocityContext; +import org.apache.velocity.app.VelocityEngine; +import org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader; +import org.jbehave.core.story.codegen.CodeGenerator; +import org.jbehave.core.story.codegen.domain.ScenarioDetails; +import org.jbehave.core.story.codegen.domain.StoryDetails; +import org.jbehave.core.util.CamelCaseConverter; + +/** + * Velocity-based code generator + * + * @author Mauro Talevi + */ +public class VelocityCodeGenerator implements CodeGenerator { + + private static final String SOURCE_PATH = "{0}/{1}s/{2}.java"; + private static final String TEMPLATE_PATH = "org/jbehave/core/story/codegen/velocity/templates/{0}.template"; + private static final String PACKAGE_NAME = "{0}.{1}s"; + + private String rootSourceDirectory; + private String rootPackageName; + + /** The velocity engine */ + private VelocityEngine engine; + + /** + * Creates a VelocityCodeGenerator + * + * @param rootSourceDirectory the root source directory of the generated + * story code + * @param rootPackageName the root package name of the story + */ + public VelocityCodeGenerator(String rootSourceDirectory, String rootPackageName) { + this.rootSourceDirectory = rootSourceDirectory; + this.rootPackageName = rootPackageName; + this.engine = new VelocityEngine(); + initialiseEngine(engine); + } + + public void generateStory(StoryDetails storyDetails) { + for (Iterator i = storyDetails.scenarios.iterator(); i.hasNext();) { + ScenarioDetails scenario = (ScenarioDetails) i.next(); + generateSource(scenario.event.name, "event"); + for (Iterator j = scenario.context.givens.iterator(); j.hasNext();) { + generateSource((String) j.next(), "given"); + } + for (Iterator j = scenario.outcome.outcomes.iterator(); j.hasNext();) { + generateSource((String) j.next(), "outcome"); + } + } + } + + private String toCamelCase(String name) { + return new CamelCaseConverter(name).toCamelCase(); + } + + private void generateSource(String name, String type) { + String className = toCamelCase(name); + String sourcePath = MessageFormat.format(SOURCE_PATH, new Object[] { rootSourceDirectory, type, className }); + String templatePath = MessageFormat.format(TEMPLATE_PATH, new Object[] { type }); + String packageName = MessageFormat.format(PACKAGE_NAME, new Object[] { rootPackageName, type }); + generateSource(sourcePath, templatePath, className, packageName); + } + + private void generateSource(String sourcePath, String templatePath, String className, String packageName) { + try { + VelocityContext context = new VelocityContext(); + context.put("className", className); + context.put("packageName", packageName); + File file = new File(sourcePath); + file.getParentFile().mkdirs(); + Writer writer = new FileWriter(file); + process(templatePath, context, writer); + writer.close(); + } catch (IOException e) { + throw new RuntimeException("Failed to generate source", e); + } + } + + /** + * Initialises VelocityEngine to retrieve resources from classpath + * + * @param engine the VelocityEngine + */ + private void initialiseEngine(VelocityEngine engine) { + try { + Properties properties = new Properties(); + properties.setProperty(VelocityEngine.RESOURCE_LOADER, "classpath"); + properties.setProperty("classpath." + VelocityEngine.RESOURCE_LOADER + ".class", + ClasspathResourceLoader.class.getName()); + engine.init(properties); + } catch (Exception e) { + throw new RuntimeException("Failed to initialise VelocityEngine " + engine, e); + } + } + + /** + * Processes a template with context + * + * @param resource the template resource + * @param context the VelocityContext + * @param writer the Writer to merge into + */ + private void process(String resource, VelocityContext context, Writer writer) { + try { + Template template = engine.getTemplate(resource); + template.merge(context, writer); + } catch (Exception e) { + throw new RuntimeException("Failed to process template " + resource + " with context " + context, e); + } + } + +}
Added: trunk/core/src/java/org/jbehave/core/story/codegen/velocity/templates/event.template (0 => 755)
--- trunk/core/src/java/org/jbehave/core/story/codegen/velocity/templates/event.template (rev 0) +++ trunk/core/src/java/org/jbehave/core/story/codegen/velocity/templates/event.template 2007-07-11 22:10:48 UTC (rev 755) @@ -0,0 +1,12 @@ +package ${packageName}; + +import org.jbehave.core.minimock.story.domain.EventUsingMiniMock; +import org.jbehave.core.story.domain.World; + +public class ${className} extends EventUsingMiniMock { + + public void occurIn(World world) { + // TODO + } + +}
Added: trunk/core/src/java/org/jbehave/core/story/codegen/velocity/templates/given.template (0 => 755)
--- trunk/core/src/java/org/jbehave/core/story/codegen/velocity/templates/given.template (rev 0) +++ trunk/core/src/java/org/jbehave/core/story/codegen/velocity/templates/given.template 2007-07-11 22:10:48 UTC (rev 755) @@ -0,0 +1,12 @@ +package ${packageName}; + +import org.jbehave.core.minimock.story.domain.GivenUsingMiniMock; +import org.jbehave.core.story.domain.World; + +public class ${className} extends GivenUsingMiniMock { + + public void setUp(World world) { + // TODO + } + +}
Added: trunk/core/src/java/org/jbehave/core/story/codegen/velocity/templates/outcome.template (0 => 755)
--- trunk/core/src/java/org/jbehave/core/story/codegen/velocity/templates/outcome.template (rev 0) +++ trunk/core/src/java/org/jbehave/core/story/codegen/velocity/templates/outcome.template 2007-07-11 22:10:48 UTC (rev 755) @@ -0,0 +1,12 @@ +package ${packageName}; + +import org.jbehave.core.minimock.story.domain.OutcomeUsingMiniMock; +import org.jbehave.core.story.domain.World; + +public class ${className} extends OutcomeUsingMiniMock { + + public void verify(World world) { + // TODO + } + +}
To unsubscribe from this list please visit:
