All Downloads are FREE. Search and download functionalities are using the official Maven repository.

ch.powerunit.extensions.matchers.ProvideMatchers Maven / Gradle / Ivy

Go to download

This is a test framework for the JDK 1.8 - Extension to provide matchers based on annotation. - Factory Support

There is a newer version: 0.1.6
Show newest version
/**
 * Powerunit - A JDK1.8 test framework
 * Copyright (C) 2014 Mathieu Boretti.
 *
 * This file is part of Powerunit
 *
 * Powerunit is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Powerunit is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Powerunit. If not, see .
 */
package ch.powerunit.extensions.matchers;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * This annotation can be used on a java class, to mark this class as supporting
 * generation of hamcrest matcher.
 * 

* This annotation is not supported on interface and enum. A warning will be * displayed in this case. *

* This annotation is processed by an annotation processor, in order to generate * : *

    *
  • One class for each annotated classes, that will contains Hamcrest * Matchers for the class.
  • *
  • In case the annotation processor parameter * "{@code ch.powerunit.extensions.matchers.provideprocessor.ProvidesMatchersAnnotationsProcessor.factory}" * is set, this value define the fully qualified name of a interface that will * be generated and will contains all start method allowing to create * instance of the various matchers.
  • *
*

* The generated classes are related with the hamcrest framework ; This * library will be required in the classpath in order to compile or run the * generated classes. *

* Concept regarding the generated Matchers *

* Hamcrest Matchers can be used, for example, with test framework (JUnit, * PowerUnit, etc.) to validate expectation on object. Hamcrest provides several * matchers to validate some information of an object (is an instance of, is, an * array contains some value, etc.), but can't provide ready to use matcher for * your own object. When trying to validate properties of object, no syntaxic * sugar (ie. autocompletion) are available and only the generic method can be * used. *

* With this annotation, it is possible to provide builder-like method, * based on hamcrest, to validate fields of an object. To do so, the annotation * processor do the following : *

    *
  • For each public field or public method starting with {@code get} or * {@code is} without any argument, generated a private matcher based on the * {@link org.hamcrest.FeatureMatcher} for this field ; this will provide a way * to validate the value of one specific property.
  • *
  • Generate an interface and the related implementation of a matcher (which * is also a builder) on the annotated classes itself, which will validate all * of the properties.
  • *
  • Generate various methods, with a name based on the annotated class, to * start the creation of the matcher.
  • *
* The annotation processor will also generate javadoc and try to retrieve from * the javadoc of the annotated element the information regarding generic * attribute. *

* The processor will also try, for field which are not based on generics, to * link the generated matchers between them, in order to provide chaining of the * Fields. *

* First example *

* Let's assume the following class, containing one single field, will be * processed by the annotation processor : * *

 * package ch.powerunit.extensions.matchers.samples;
 *
 * import ch.powerunit.extensions.matchers.ProvideMatchers;
 *
 * @ProvideMatchers
 * public class SimplePojo {
 * 	public String oneField;
 * }
 * 
* * In this case a class named {@code SimplePojoMatchers} will be generated. As a * public interface, the following methods will be available : *
    *
  • {@code public static SimplePojoMatcher simplePojoWith()}: This will * return a matcher (see below), which by default matches any instance of the * SimplePojo class.
  • *
  • * {@code public static SimplePojoMatcher simplePojoWithSameValue(SimplePojo other)} * : This will return a matcher, which by default matches an instance of the * SimplePojo having the field {@code oneField} matching (Matcher {@code is} of * hamcrest) of the reference object.
  • *
* The returned interface is already a correct hamcrest matcher. This interface * provide method that set the expectating on the various fields. As in this * case, where is only one field, the returned interface ensure that once the * expected is defined, it is not possible to modify it. Depending of the type * of the field, various methods are generated to define the expectation : *
    *
  • Two standards methods are defined for all type of fields : {@code Matcher * oneField(Matcher matcher)} and * {@code Matcher oneField(String value)}. The second one is a * shortcut to validate the field with the {@code is} Matcher and the first one * accept another matcher ; The method with matcher parameter ensures that it is * possible to combine any other matcher provided by hamcrest or any others * extensions. *
  • As the field is a String, others special expectation (shortcut) are * provided, for example : {@code oneFieldComparesEqualTo}, * {@code oneFieldLessThan}, {@code oneFieldStartsWith}, etc.
  • *
* Second example *

* In case the annotated contains several fields, the generated DSL * provide chained methods, for example * {@code TwoFieldsPojoMatcher firstField(Matcher matcher)} and * {@code TwoFieldsPojoMatcher secondField(Matcher matcher)}. * * Also, depending on the class, other with methods may be provided. *

* Usage example *

* Assuming powerunit as a test framework, the usage of the matcher will look * like : * *

 * @Test
 * public void testOKMatcherWithComparable() {
 * 	Pojo1 p = new Pojo1();
 * 	p.msg2 = "12";
 * 	assertThat(p).is(Pojo1Matchers.pojo1With().msg2ComparesEqualTo("12"));
 * }
 * 
 * 
* * Assuming the {@code msg2} is change to the value {@code 11}, the resulting * unit test error will look like (the Pojo1 classes contains several fields) : * *
 * expecting an instance of ch.powerunit.extensions.matchers.samples.Pojo1 with
 * [msg2 a value equal to "12"]
 * [msg3 ANYTHING]
 * [msg4 ANYTHING]
 * [msg5 ANYTHING]
 * [msg6 ANYTHING]
 * [msg7 ANYTHING]
 * [msg8 ANYTHING]
 * [msg9 ANYTHING]
 * [msg12 ANYTHING]
 * [msg1 ANYTHING]
 * [myBoolean ANYTHING]
 * [oneBoolean ANYTHING]
 * but [msg2 "11" was less than "12"]
 * 
 * 
* *
*

* Overriding the way the matchers are generated *

    *
  • The attribute {@link #matchersClassName() matchersClassName} may be used * to change the simple name (NOT THE FULLY QUALIFIED NAME) of the * generated class.
  • *
  • The attribute {@link #matchersPackageName() matchersPackageName} may be * used to change the package name of the generated class.
  • *
*
*

* Extensions *

* The framework, since version 0.1.0, is able to detect others library and use * it : *

    *
  • If Hamcrest Date * is available, additional DSL method are added for the Java 8 Date objects. *
  • *
  • If Hamcrest 1.3 * Utility Matchers is available, additional DSL method are added for the * collections.
  • *
  • If Spotify Hamcrest * (jackson) is available and the {@link #JSON_EXTENSION} is used on * {@link #extensions()}, then method to validate String as json are added.
  • *
  • If Bean Matchers is * available additional method to validate Class field.
  • *
* * @author borettim * */ @Documented @Retention(RetentionPolicy.SOURCE) @Target({ ElementType.TYPE }) @Inherited public @interface ProvideMatchers { /** * This attribute may be used to override the default class name that will * contains the generated matchers. *

* By default, this attribute is an empty string, which indicate to use * the default construction pattern. *

* By default, the Matchers class name is the name of the annotated class, * followed by {@code Matchers}. * * @return the name of the matchers class or an empty string if this is not * overloaded. */ String matchersClassName() default ""; /** * This attribute may be used to override the default package name that will * be used for the generated matchers. *

* By default, this attribute is an empty string, which indicate to use * the default construction pattern. *

* By default, the Matchers package name is the same that the annotated * class. * * @return the name of the matchers package or an empty string if this is * not overloaded. */ String matchersPackageName() default ""; /** * This attribute may be used to set a comments that will be passed inside * the {@link javax.annotation.Generated#comments() comments} attribute of * the {@link javax.annotation.Generated @Generated} annotation. * * @return the comments or an empty string if ignored. */ String comments() default ""; /** * This attribute may be used to generate additional exposition methods for * the object. *

* By default, only the standard method are generated. * * @return additional method to be generated or an empty array by default. * @since 0.1.0 */ ComplementaryExpositionMethod[]moreMethod() default {}; /** * This attribute may be used to enable some extensions for this objects. *

* By default, no extension are enabled. * * @return the extension to be used or an empty array by default. * @since 0.1.0 * @see #JSON_EXTENSION An extension to add a validation on String, as JSON, * based on the * Spotify * Matchers. */ String[]extensions() default {}; /** * May be use as part of {@link #extensions()} to enable, if available, an * extension an each String to be validated by using a json validation. * * * @since 0.1.0 */ public static final String JSON_EXTENSION = "json-extension"; }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy