/**
* Copyright 2012-2017 Gunnar Morling (http://www.gunnarmorling.de/)
* and/or other contributors as indicated by the @authors tag. See the
* copyright.txt file in the distribution for a full listing of all
* contributors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.mapstruct.ap.testutil.runner;
import java.io.File;
import java.io.UnsupportedEncodingException;
import java.net.URL;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.List;
import org.junit.rules.TestRule;
import org.junit.runner.Description;
import org.junit.runners.model.Statement;
import org.mapstruct.ap.testutil.assertions.JavaFileAssert;
import static org.assertj.core.api.Assertions.fail;
/**
* A {@link TestRule} to perform assertions on generated source files.
* <p>
* To add it to the test, use:
*
* <pre>
* @Rule
* public GeneratedSource generatedSources = new GeneratedSource();
* </pre>
*
* @author Andreas Gudian
*/
public class GeneratedSource implements TestRule {
private static final String FIXTURES_ROOT = "fixtures/";
/**
* static ThreadLocal, as the {@link CompilingStatement} must inject itself statically for this rule to gain access
* to the statement's information. As test execution of different classes in parallel is supported.
*/
private static ThreadLocal<CompilingStatement> compilingStatement = new ThreadLocal<CompilingStatement>();
private List<Class<?>> fixturesFor = new ArrayList<Class<?>>();
@Override
public Statement apply(Statement base, Description description) {
return new GeneratedSourceStatement( base );
}
static void setCompilingStatement(CompilingStatement compilingStatement) {
GeneratedSource.compilingStatement.set( compilingStatement );
}
static void clearCompilingStatement() {
GeneratedSource.compilingStatement.remove();
}
/**
* Adds more mappers that need to be compared.
*
* The comparison is done for mappers and the are compared against a Java file that matches the name of the
* Mapper that would have been created for the fixture.
*
* @param fixturesFor the classes that need to be compared with
* @return the same rule for chaining
*/
public GeneratedSource addComparisonToFixtureFor(Class<?>... fixturesFor) {
for ( Class<?> fixture : fixturesFor ) {
this.fixturesFor.add( fixture );
}
return this;
}
/**
* @param mapperClass the class annotated with {@code @Mapper}
*
* @return an assert for the *Impl.java for the given mapper
*/
public JavaFileAssert forMapper(Class<?> mapperClass) {
String generatedJavaFileName = getMapperName( mapperClass );
return forJavaFile( generatedJavaFileName );
}
private String getMapperName(Class<?> mapperClass) {
return mapperClass.getName().replace( '.', '/' ).concat( "Impl.java" );
}
/**
* @param mapperClass the class annotated with {@code @Mapper} and {@code @DecoratedWith(..)}
*
* @return an assert for the *Impl_.java for the given mapper
*/
public JavaFileAssert forDecoratedMapper(Class<?> mapperClass) {
String generatedJavaFileName = mapperClass.getName().replace( '.', '/' ).concat( "Impl_.java" );
return forJavaFile( generatedJavaFileName );
}
/**
* @param path the path relative to the source output directory of the java file to return an assert for
*
* @return an assert for the file specified by the given path
*/
public JavaFileAssert forJavaFile(String path) {
return new JavaFileAssert( new File( compilingStatement.get().getSourceOutputDir() + "/" + path ) );
}
private class GeneratedSourceStatement extends Statement {
private final Statement next;
private GeneratedSourceStatement(Statement next) {
this.next = next;
}
@Override
public void evaluate() throws Throwable {
next.evaluate();
handleFixtureComparison();
}
}
private void handleFixtureComparison() throws UnsupportedEncodingException {
for ( Class<?> fixture : fixturesFor ) {
String expectedFixture = FIXTURES_ROOT + getMapperName( fixture );
URL expectedFile = getClass().getClassLoader().getResource( expectedFixture );
if ( expectedFile == null ) {
fail( String.format(
"No reference file could be found for Mapper %s. You should create a file %s",
fixture.getName(),
expectedFixture
) );
}
else {
File expectedResource = new File( URLDecoder.decode( expectedFile.getFile(), "UTF-8" ) );
forMapper( fixture ).hasSameMapperContent( expectedResource );
}
fixture.getPackage().getName();
}
}
}