Skip to content

Commit

Permalink
implement description generator (#55)
Browse files Browse the repository at this point in the history
  • Loading branch information
Jan Schäfer committed Jan 18, 2015
1 parent 7fa92d7 commit b43561c
Show file tree
Hide file tree
Showing 8 changed files with 175 additions and 24 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package com.tngtech.jgiven.annotation;

import java.lang.annotation.Annotation;

import com.tngtech.jgiven.config.TagConfiguration;

/**
* A default implementation of {@link com.tngtech.jgiven.annotation.TagDescriptionGenerator}.
* It just calls {@code tagConfiguration.getDescription()}.
*
* @since v0.6.3
*/
public class DefaultTagDescriptionGenerator implements TagDescriptionGenerator {
@Override
public String generateDescription( TagConfiguration tagConfiguration, Annotation annotation, Object value ) {
return tagConfiguration.getDescription();
}
}
15 changes: 15 additions & 0 deletions jgiven-core/src/main/java/com/tngtech/jgiven/annotation/IsTag.java
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,21 @@
*/
String description() default "";

/**
* An optional description generator that is used to dynamically generate
* the description depending on the concrete value of an annotation.
* <p>
* The class that implements {@link TagDescriptionGenerator} interface must
* be a public non-abstract class that is not a non-static inner class and must have a public default constructor.
* </p>
* <p>
* If this attribute is set, the {@link #description()} attribute is ignored.
* </p>
*
* @since v0.6.3
*/
Class<? extends TagDescriptionGenerator> descriptionGenerator() default DefaultTagDescriptionGenerator.class;

/**
* An optional type description that overrides the default which is the name of the annotation.
*/
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package com.tngtech.jgiven.annotation;

import java.lang.annotation.Annotation;

import com.tngtech.jgiven.config.TagConfiguration;

/**
* Is used as an attribute of the {@link com.tngtech.jgiven.annotation.IsTag} annotation
* to dynamically generate a description for an annotation depending on its value.
* <p>
* Implementations of this interface must be a public non-abstract class that is not a non-static inner class
* and must have a public default constructor.
* </p>
*
* @since v0.6.3
*/
public interface TagDescriptionGenerator {

/**
* Implement this method to generate the description for the given annotation and its value.
* <p>
* Note that when the value of the annotation is an array and {@link com.tngtech.jgiven.annotation.IsTag#explodeArray()}
* is {@code true}, then this method is called for each value of the array and not once for the whole array.
* Otherwise it is called only once.
* </p>
* @param tagConfiguration the configuration of the tag. The values typically correspond to the {@link IsTag annotation}.
* However, it is also possible to configure annotations to be tags using {@link com.tngtech.jgiven.annotation.JGivenConfiguration},
* in which case there is no {@link IsTag} annotation.
* @param annotation the actual annotation that was used as a tag
* @param value the value of the annotation. If the annotation has no value the default value is passed ({@link com.tngtech.jgiven.annotation.IsTag#value()}
*
* @return the description of the annotation for the given value
*/
String generateDescription( TagConfiguration tagConfiguration, Annotation annotation, Object value );
}
Original file line number Diff line number Diff line change
@@ -1,14 +1,22 @@
package com.tngtech.jgiven.config;

import com.tngtech.jgiven.annotation.DefaultTagDescriptionGenerator;
import com.tngtech.jgiven.annotation.IsTag;
import com.tngtech.jgiven.annotation.TagDescriptionGenerator;

/**
* Represents the configuration of a tag.
*
* @see com.tngtech.jgiven.annotation.IsTag for a documentation of the different values.
*/
public class TagConfiguration {
boolean ignoreValue;
boolean explodeArray = true;
boolean prependType = false;
String defaultValue = "";
String description = "";
String type = "";
private boolean ignoreValue;
private boolean explodeArray = true;
private boolean prependType;
private String defaultValue = "";
private String description = "";
private Class<? extends TagDescriptionGenerator> descriptionGenerator = DefaultTagDescriptionGenerator.class;
private String type = "";

public static class Builder {
final TagConfiguration configuration;
Expand Down Expand Up @@ -37,6 +45,11 @@ public Builder description( String s ) {
return this;
}

public Builder descriptionGenerator( Class<? extends TagDescriptionGenerator> descriptionGenerator ) {
configuration.descriptionGenerator = descriptionGenerator;
return this;
}

public Builder type( String s ) {
configuration.type = s;
return this;
Expand All @@ -48,26 +61,58 @@ public Builder prependType( boolean b ) {
}
}

/**
* {@link com.tngtech.jgiven.annotation.IsTag#value()}
* @see com.tngtech.jgiven.annotation.IsTag
*/
public String getDefaultValue() {
return defaultValue;
}

/**
* {@link com.tngtech.jgiven.annotation.IsTag#description()}
* @see com.tngtech.jgiven.annotation.IsTag
*/
public String getDescription() {
return description;
}

/**
* {@link com.tngtech.jgiven.annotation.IsTag#descriptionGenerator()}
* @see com.tngtech.jgiven.annotation.IsTag
*/
public Class<? extends TagDescriptionGenerator> getDescriptionGenerator() {
return descriptionGenerator;
}

/**
* {@link com.tngtech.jgiven.annotation.IsTag#type()}
* @see com.tngtech.jgiven.annotation.IsTag
*/
public String getType() {
return type;
}

/**
* {@link com.tngtech.jgiven.annotation.IsTag#explodeArray()}
* @see com.tngtech.jgiven.annotation.IsTag
*/
public boolean isExplodeArray() {
return explodeArray;
}

/**
* {@link com.tngtech.jgiven.annotation.IsTag#ignoreValue()}
* @see com.tngtech.jgiven.annotation.IsTag
*/
public boolean isIgnoreValue() {
return ignoreValue;
}

/**
* {@link com.tngtech.jgiven.annotation.IsTag#prependType()}
* @see com.tngtech.jgiven.annotation.IsTag
*/
public boolean isPrependType() {
return prependType;
}
Expand All @@ -80,6 +125,7 @@ public static TagConfiguration fromIsTag( IsTag isTag ) {
result.ignoreValue = isTag.ignoreValue();
result.prependType = isTag.prependType();
result.type = isTag.type();
result.descriptionGenerator = isTag.descriptionGenerator();
return result;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,8 @@ public class JGivenWrongUsageException extends RuntimeException {
public JGivenWrongUsageException( String message ) {
super( message );
}

public JGivenWrongUsageException( String message, Exception e ) {
super( message, e );
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import com.tngtech.jgiven.config.ConfigurationUtil;
import com.tngtech.jgiven.config.DefaultConfiguration;
import com.tngtech.jgiven.config.TagConfiguration;
import com.tngtech.jgiven.exception.JGivenWrongUsageException;
import com.tngtech.jgiven.format.DefaultFormatter;
import com.tngtech.jgiven.format.PrintfFormatter;
import com.tngtech.jgiven.format.TableFormatter;
Expand Down Expand Up @@ -331,32 +332,27 @@ public List<Tag> toTags( Annotation annotation ) {
tag.setPrependType( true );
}

if( tagConfig.getDescription() != null ) {
tag.setDescription( tagConfig.getDescription() );
}

Object value = tagConfig.getDefaultValue();
if( !Strings.isNullOrEmpty( tagConfig.getDefaultValue() ) ) {
tag.setValue( tagConfig.getDefaultValue() );
}

if( tagConfig.isIgnoreValue() ) {
tag.setDescription( getDescriptionFromGenerator( tagConfig, annotation, value ) );
return Arrays.asList( tag );
}

try {
Method method = annotationType.getMethod( "value" );
Object value = method.invoke( annotation );
value = method.invoke( annotation );
if( value != null ) {
if( value.getClass().isArray() ) {
Object[] array = (Object[]) value;
List<String> values = Lists.newArrayList();
for( Object v : array ) {
values.add( String.valueOf( v ) );
}
Object[] objectArray = (Object[]) value;
if( tagConfig.isExplodeArray() ) {
return getExplodedTags( tag, values );
return getExplodedTags( tag, objectArray, annotation, tagConfig );
}
tag.setValue( values );
tag.setValue( toStringList( objectArray ) );

} else {
tag.setValue( String.valueOf( value ) );
}
Expand All @@ -367,15 +363,35 @@ public List<Tag> toTags( Annotation annotation ) {
log.error( "Error while getting 'value' method of annotation " + annotation, e );
}

tag.setDescription( getDescriptionFromGenerator( tagConfig, annotation, value ) );
return Arrays.asList( tag );
}

private static List<Tag> getExplodedTags( Tag originalTag, List<String> values ) {
private List<String> toStringList( Object[] value ) {
Object[] array = value;
List<String> values = Lists.newArrayList();
for( Object v : array ) {
values.add( String.valueOf( v ) );
}
return values;
}

private String getDescriptionFromGenerator( TagConfiguration tagConfiguration, Annotation annotation, Object value ) {
try {
return tagConfiguration.getDescriptionGenerator().newInstance().generateDescription( tagConfiguration, annotation, value );
} catch( Exception e ) {
throw new JGivenWrongUsageException( "Error while trying to generate the description for annotation " + annotation
+ " using DescriptionGenerator class " + tagConfiguration.getDescriptionGenerator() + ": " + e.getMessage(), e );
}
}

private List<Tag> getExplodedTags( Tag originalTag, Object[] values, Annotation annotation, TagConfiguration tagConfig ) {
List<Tag> result = Lists.newArrayList();
for( String singleValue : values ) {
Tag newTag = new Tag( originalTag.getName(), singleValue );
for( Object singleValue : values ) {
Tag newTag = new Tag( originalTag.getName(), String.valueOf( singleValue ) );
newTag.setDescription( originalTag.getDescription() );
newTag.setPrependType( originalTag.isPrependType() );
newTag.setDescription( getDescriptionFromGenerator( tagConfig, annotation, singleValue ) );
result.add( newTag );
}
return result;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.tngtech.jgiven.tags;

import java.lang.annotation.Annotation;

import com.tngtech.jgiven.annotation.TagDescriptionGenerator;
import com.tngtech.jgiven.config.TagConfiguration;

public class IssueDescriptionGenerator implements TagDescriptionGenerator {
private static final String ISSUE_URL = "https://github.com/TNG/JGiven/issues/";

@Override
public String generateDescription( TagConfiguration tagConfiguration, Annotation annotation, Object value ) {
String valueAsString = String.valueOf( value );
return String.format( "Scenarios of <a href='%s%s'>Issue %s</a>", ISSUE_URL, valueAsString.substring( 1 ), valueAsString );
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,15 @@

import com.tngtech.jgiven.config.AbstractJGivenConfiguraton;
import com.tngtech.jgiven.tags.Issue;
import com.tngtech.jgiven.tags.IssueDescriptionGenerator;

public class JGivenTestConfiguration extends AbstractJGivenConfiguraton {

@Override
public void configure() {
configureTag( Issue.class )
.prependType( true )
.description( "Issue numbers correspond to Issues in GitHub" );
configureTag(Issue.class)
.prependType(true)
.descriptionGenerator(IssueDescriptionGenerator.class);
}

}

0 comments on commit b43561c

Please sign in to comment.