package org.jbehave.core.configuration.pico; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.hasItems; import static org.hamcrest.Matchers.instanceOf; import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.sameInstance; import static org.jbehave.core.reporters.Format.CONSOLE; import static org.jbehave.core.reporters.Format.HTML; import static org.jbehave.core.reporters.Format.STATS; import static org.jbehave.core.reporters.Format.TXT; import static org.jbehave.core.reporters.Format.XML; import static org.mockito.Matchers.isA; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import java.text.DateFormat; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; import java.util.List; import java.util.Locale; import java.util.Properties; import org.jbehave.core.annotations.Configure; import org.jbehave.core.annotations.UsingSteps; import org.jbehave.core.annotations.pico.UsingPico; import org.jbehave.core.configuration.AnnotationBuilder; import org.jbehave.core.configuration.AnnotationMonitor; import org.jbehave.core.configuration.Configuration; import org.jbehave.core.configuration.Keywords; import org.jbehave.core.configuration.MostUsefulConfiguration; import org.jbehave.core.embedder.StoryControls; import org.jbehave.core.failures.FailureStrategy; import org.jbehave.core.failures.SilentlyAbsorbingFailure; import org.jbehave.core.i18n.LocalizedKeywords; import org.jbehave.core.io.LoadFromURL; import org.jbehave.core.io.StoryLoader; import org.jbehave.core.parsers.RegexPrefixCapturingPatternParser; import org.jbehave.core.parsers.StepPatternParser; import org.jbehave.core.reporters.StoryReporterBuilder; import org.jbehave.core.steps.CandidateSteps; import org.jbehave.core.steps.ParameterConverters; import org.jbehave.core.steps.Steps; import org.jbehave.core.steps.ParameterConverters.DateConverter; import org.jbehave.core.steps.ParameterConverters.ParameterConverter; import org.jbehave.core.steps.pico.PicoStepsFactoryBehaviour.FooSteps; import org.jbehave.core.steps.pico.PicoStepsFactoryBehaviour.FooStepsWithDependency; import org.junit.Assert; import org.junit.Test; import org.picocontainer.MutablePicoContainer; import org.picocontainer.PicoContainer; public class PicoAnnotationBuilderBehaviour { @Test public void shouldBuildConfigurationFromAnnotations() { PicoAnnotationBuilder builder = new PicoAnnotationBuilder(AnnotatedUsingPico.class); Configuration configuration = builder.buildConfiguration(); assertThat(configuration.storyControls().dryRun(), is(true)); assertThat(configuration.storyControls().skipScenariosAfterFailure(), is(true)); assertThat(configuration.failureStrategy(), instanceOf(SilentlyAbsorbingFailure.class)); assertThat(configuration.storyLoader(), instanceOf(LoadFromURL.class)); assertThat(configuration.stepPatternParser(), instanceOf(RegexPrefixCapturingPatternParser.class)); assertThat(((RegexPrefixCapturingPatternParser) configuration.stepPatternParser()).getPrefix(), equalTo("MyPrefix")); assertThatDateIsConvertedWithFormat(configuration.parameterConverters(), new SimpleDateFormat("yyyy-MM-dd")); assertThat(configuration.storyReporterBuilder().formats(), hasItems(CONSOLE, HTML, TXT, XML, STATS)); Keywords keywords = configuration.storyReporterBuilder().keywords(); assertThat(keywords, instanceOf(LocalizedKeywords.class)); assertThat(((LocalizedKeywords) keywords).getLocale(), equalTo(Locale.ITALIAN)); assertThat(configuration.storyReporterBuilder().outputDirectory().getName(), equalTo("my-output-directory")); assertThat(configuration.storyReporterBuilder().viewResources().getProperty("index"), equalTo("my-reports-index.ftl")); assertThat(configuration.storyReporterBuilder().viewResources().getProperty("decorateNonHtml"), equalTo("true")); assertThat(configuration.storyReporterBuilder().reportFailureTrace(), is(true)); } private void assertThatDateIsConvertedWithFormat(ParameterConverters parameterConverters, DateFormat dateFormat) { String date = "2010-10-10"; try { assertThat((Date) parameterConverters.convert(date, Date.class), equalTo(dateFormat.parse(date))); } catch (ParseException e) { Assert.fail(); } } @Test public void shouldBuildDefaultConfigurationIfAnnotationOrAnnotatedValuesNotPresent() { PicoAnnotationBuilder builderNotAnnotated = new PicoAnnotationBuilder(NotAnnotated.class); assertThatConfigurationIs(builderNotAnnotated.buildConfiguration(), new MostUsefulConfiguration()); PicoAnnotationBuilder builderAnnotatedWithoutLocations = new PicoAnnotationBuilder( AnnotatedWithoutModules.class); assertThatConfigurationIs(builderAnnotatedWithoutLocations.buildConfiguration(), new MostUsefulConfiguration()); } private void assertThatConfigurationIs(Configuration builtConfiguration, Configuration defaultConfiguration) { assertThat(builtConfiguration.failureStrategy(), instanceOf(defaultConfiguration.failureStrategy().getClass())); assertThat(builtConfiguration.storyLoader(), instanceOf(defaultConfiguration.storyLoader().getClass())); assertThat(builtConfiguration.stepPatternParser(), instanceOf(defaultConfiguration.stepPatternParser() .getClass())); assertThat(builtConfiguration.storyReporterBuilder().formats(), equalTo(defaultConfiguration .storyReporterBuilder().formats())); assertThat(builtConfiguration.storyReporterBuilder().outputDirectory(), equalTo(defaultConfiguration .storyReporterBuilder().outputDirectory())); assertThat(builtConfiguration.storyReporterBuilder().viewResources(), equalTo(defaultConfiguration .storyReporterBuilder().viewResources())); assertThat(builtConfiguration.storyReporterBuilder().reportFailureTrace(), equalTo(defaultConfiguration .storyReporterBuilder().reportFailureTrace())); } @Test public void shouldBuildCandidateStepsFromAnnotationsUsingPico() { PicoAnnotationBuilder builderAnnotated = new PicoAnnotationBuilder(AnnotatedUsingPico.class); Configuration configuration = builderAnnotated.buildConfiguration(); assertThatStepsInstancesAre(builderAnnotated.buildCandidateSteps(configuration), FooSteps.class, FooStepsWithDependency.class); } @Test public void shouldBuildCandidateStepsFromAnnotationsUsingStepsAndPico() { PicoAnnotationBuilder builderAnnotated = new PicoAnnotationBuilder(AnnotatedUsingStepsAndPico.class); Configuration configuration = builderAnnotated.buildConfiguration(); assertThatStepsInstancesAre(builderAnnotated.buildCandidateSteps(configuration), FooSteps.class); } @Test public void shouldBuildCandidateStepsFromAnnotationsUsingStepsAndInheritingPicoFromParent() { AnnotationBuilder builderAnnotated = new PicoAnnotationBuilder(InheritingAnnotatedUsingSteps.class); Configuration configuration = builderAnnotated.buildConfiguration(); assertThatStepsInstancesAre(builderAnnotated.buildCandidateSteps(configuration), FooSteps.class); } @Test public void shouldBuildEmptyStepsListIfAnnotationOrAnnotatedValuesNotPresent() { PicoAnnotationBuilder builderNotAnnotated = new PicoAnnotationBuilder(NotAnnotated.class); assertThatStepsInstancesAre(builderNotAnnotated.buildCandidateSteps()); PicoAnnotationBuilder builderAnnotatedWithoutModules = new PicoAnnotationBuilder(AnnotatedWithoutModules.class); assertThatStepsInstancesAre(builderAnnotatedWithoutModules.buildCandidateSteps()); } @Test public void shouldNotBuildContainerIfModuleNotInstantiable() { AnnotationMonitor annotationMonitor = mock(AnnotationMonitor.class); PicoAnnotationBuilder builderPrivateModule = new PicoAnnotationBuilder(AnnotatedWithPrivateModule.class, annotationMonitor); assertThatStepsInstancesAre(builderPrivateModule.buildCandidateSteps()); verify(annotationMonitor).elementCreationFailed(isA(Class.class), isA(Exception.class)); } @Test public void shouldCreateOnlyOneContainerForMultipleBuildInvocations() { PicoAnnotationBuilder builderAnnotated = new PicoAnnotationBuilder(AnnotatedUsingStepsAndPico.class); builderAnnotated.buildConfiguration(); PicoContainer picoContainer = builderAnnotated.picoContainer(); builderAnnotated.buildConfiguration(); assertThat(builderAnnotated.picoContainer(), sameInstance(picoContainer)); } private void assertThatStepsInstancesAre(List<CandidateSteps> candidateSteps, Class<?>... stepsClasses) { assertThat(candidateSteps.size(), equalTo(stepsClasses.length)); for (int i = 0; i < stepsClasses.length; i++) { assertThat(((Steps) candidateSteps.get(i)).instance(), instanceOf(stepsClasses[i])); } } @Configure() @UsingPico(modules = { ConfigurationModule.class, StepsModule.class }) private static class AnnotatedUsingPico { } @Configure() @UsingPico(modules = { ConfigurationModule.class }) private static class ParentAnnotatedUsingPico { } @UsingSteps(instances = { FooSteps.class }) private static class InheritingAnnotatedUsingSteps extends ParentAnnotatedUsingPico { } @Configure() @UsingSteps(instances = { FooSteps.class }) @UsingPico(modules = { ConfigurationModule.class }) private static class AnnotatedUsingStepsAndPico { } @Configure() @UsingPico() private static class AnnotatedWithoutModules { } @Configure() @UsingPico(modules = { PrivateModule.class }) private static class AnnotatedWithPrivateModule { } private static class NotAnnotated { } public static class ConfigurationModule implements PicoModule { public void configure(MutablePicoContainer container) { container.addComponent(StoryControls.class, new StoryControls().doDryRun(true).doSkipScenariosAfterFailure(true)); container.addComponent(FailureStrategy.class, SilentlyAbsorbingFailure.class); container.addComponent(StepPatternParser.class, new RegexPrefixCapturingPatternParser("MyPrefix")); container.addComponent(StoryLoader.class, new LoadFromURL()); container.addComponent(ParameterConverter.class, new DateConverter(new SimpleDateFormat("yyyy-MM-dd"))); Properties viewResources = new Properties(); viewResources.setProperty("index", "my-reports-index.ftl"); viewResources.setProperty("decorateNonHtml", "true"); container.addComponent(new StoryReporterBuilder().withDefaultFormats().withFormats(CONSOLE, HTML, TXT, XML) .withKeywords(new LocalizedKeywords(Locale.ITALIAN)).withRelativeDirectory("my-output-directory") .withViewResources(viewResources).withFailureTrace(true)); } } public static class StepsModule implements PicoModule { public void configure(MutablePicoContainer container) { container.addComponent(FooSteps.class); container.addComponent(Integer.class, 42); container.addComponent(FooStepsWithDependency.class); } } private static class PrivateModule implements PicoModule { public void configure(MutablePicoContainer container) { container.addComponent(StoryLoader.class, new LoadFromURL()); } } }