Convert groovy to java (spring-cloud-contract-verifier module) (#1476)

* Convert groovy to java (gh-1470)

Co-authored-by: Anatolii Zhmaiev <Anatolii_Zhmaiev@epam.com>
This commit is contained in:
Anatolii Zhmaiev
2020-08-20 19:13:24 +03:00
committed by GitHub
parent 8f201d0c6c
commit c5d3456d3a
215 changed files with 1314 additions and 1216 deletions

View File

@@ -1,68 +0,0 @@
/*
* Copyright 2013-2020 the original author or authors.
*
* 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
*
* https://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.springframework.cloud.contract.verifier
import java.nio.file.Files
import java.nio.file.Path
import java.nio.file.Paths
import java.nio.file.StandardOpenOption
import groovy.transform.CompileStatic
import groovy.transform.PackageScope
import groovy.util.logging.Commons
import org.springframework.cloud.contract.verifier.builder.SingleTestGenerator
import static org.springframework.cloud.contract.verifier.util.NamesUtil.beforeLast
import static org.springframework.cloud.contract.verifier.util.NamesUtil.capitalize
import static org.springframework.cloud.contract.verifier.util.NamesUtil.packageToDirectory
@CompileStatic
@PackageScope
@Commons
class FileSaver {
private final File targetDirectory
private final SingleTestGenerator generator
private final String fileExtension
FileSaver(File targetDirectory, String fileExtension, SingleTestGenerator generator) {
this.targetDirectory = targetDirectory
this.generator = generator
this.fileExtension = fileExtension
}
void saveClassFile(Path classPath, byte[] classBytes) {
log.info("Creating new class file [$classPath]")
Files.
write(classPath, classBytes, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING)
}
protected Path pathToClass(Path testBaseDir, String fileName) {
return Paths.get(testBaseDir.toString(),
capitalize(fileName) + fileExtension).toAbsolutePath()
}
protected Path generateTestBaseDir(String basePackageClass, String includedDirectoryRelativePath) {
Path testBaseDir = Paths.
get(targetDirectory.absolutePath, packageToDirectory(basePackageClass),
beforeLast(includedDirectoryRelativePath, File.separator))
Files.createDirectories(testBaseDir)
return testBaseDir
}
}

View File

@@ -1,197 +0,0 @@
/*
* Copyright 2013-2020 the original author or authors.
*
* 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
*
* https://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.springframework.cloud.contract.verifier
import java.nio.charset.StandardCharsets
import java.nio.file.Path
import java.util.concurrent.atomic.AtomicInteger
import groovy.transform.CompileDynamic
import groovy.transform.CompileStatic
import groovy.transform.PackageScope
import org.apache.commons.logging.Log
import org.apache.commons.logging.LogFactory
import org.springframework.cloud.contract.spec.ContractVerifierException
import org.springframework.cloud.contract.verifier.builder.JavaTestGenerator
import org.springframework.cloud.contract.verifier.builder.SingleTestGenerator
import org.springframework.cloud.contract.verifier.config.ContractVerifierConfigProperties
import org.springframework.cloud.contract.verifier.file.ContractFileScanner
import org.springframework.cloud.contract.verifier.file.ContractFileScannerBuilder
import org.springframework.cloud.contract.verifier.file.ContractMetadata
import org.springframework.cloud.contract.verifier.util.NamesUtil
import org.springframework.core.io.support.SpringFactoriesLoader
import org.springframework.util.MultiValueMap
import org.springframework.util.StringUtils
import static org.springframework.cloud.contract.verifier.util.NamesUtil.afterLast
import static org.springframework.cloud.contract.verifier.util.NamesUtil.beforeLast
import static org.springframework.cloud.contract.verifier.util.NamesUtil.convertIllegalPackageChars
import static org.springframework.cloud.contract.verifier.util.NamesUtil.directoryToPackage
import static org.springframework.cloud.contract.verifier.util.NamesUtil.toLastDot
/**
* @author Jakub Kubrynski, codearte.io
*/
@CompileStatic
class TestGenerator {
private static final String DEFAULT_CLASS_PREFIX = "ContractVerifier"
private static final String DEFAULT_TEST_PACKAGE = "org.springframework.cloud.contract.verifier.tests"
private static final Log log = LogFactory.getLog(TestGenerator)
private final ContractVerifierConfigProperties configProperties
private AtomicInteger counter = new AtomicInteger()
private SingleTestGenerator generator
private FileSaver saver
private ContractFileScanner contractFileScanner
TestGenerator(ContractVerifierConfigProperties configProperties) {
this(configProperties, singleTestGenerator(),
new FileSaver(configProperties.generatedTestSourcesDir, configProperties.testFramework.classExtension,
singleTestGenerator()))
}
private static SingleTestGenerator singleTestGenerator() {
List<SingleTestGenerator> factories = SpringFactoriesLoader.
loadFactories(SingleTestGenerator, null)
if (factories.empty) {
return new JavaTestGenerator()
}
return factories.first()
}
TestGenerator(ContractVerifierConfigProperties configProperties, SingleTestGenerator generator, FileSaver saver) {
this.configProperties = configProperties
if (configProperties.contractsDslDir == null) {
throw new ContractVerifierException("Stubs directory not found under " + configProperties.contractsDslDir)
}
this.generator = generator
this.saver = saver
contractFileScanner = new ContractFileScannerBuilder()
.baseDir(configProperties.contractsDslDir)
.excluded(configProperties.excludedFiles as Set)
.ignored(configProperties.ignoredFiles as Set)
.included(configProperties.includedFiles as Set)
.includeMatcher(this.configProperties.includedContracts)
.build()
}
protected TestGenerator(ContractVerifierConfigProperties configProperties, SingleTestGenerator generator, FileSaver saver, ContractFileScanner contractFileScanner) {
this.configProperties = configProperties
if (configProperties.contractsDslDir == null) {
throw new ContractVerifierException("Stubs directory not found under " + configProperties.contractsDslDir)
}
this.generator = generator
this.saver = saver
this.contractFileScanner = contractFileScanner
}
int generate() {
generateTestClasses(basePackageName())
NamesUtil.recrusiveDirectoryToPackage(configProperties.generatedTestSourcesDir)
NamesUtil.recrusiveDirectoryToPackage(configProperties.generatedTestResourcesDir)
return counter.get()
}
private String basePackageName() {
if (configProperties.basePackageForTests) {
return configProperties.basePackageForTests
}
else if (configProperties.baseClassForTests) {
return toLastDot(configProperties.baseClassForTests)
}
else if (configProperties.packageWithBaseClasses) {
return configProperties.packageWithBaseClasses
}
return DEFAULT_TEST_PACKAGE
}
@PackageScope
void generateTestClasses(final String basePackageName) {
MultiValueMap<Path, ContractMetadata> contracts = contractFileScanner.
findContractsRecursively()
if (log.isDebugEnabled()) {
log.debug("Found the following contracts " + contracts.keySet())
}
Set<Map.Entry<Path,List<ContractMetadata>>> inProgress = inProgress(contracts)
if (!inProgress.isEmpty() && configProperties.failOnInProgress) {
throw new IllegalStateException("In progress contracts found in paths [" + inProgress.collect { it.key.toString() }.join(",") + "] and the switch [failOnInProgress] is set to [true]. Either unmark those contracts as in progress, or set the switch to [false].")
}
processAllNotInProgress(contracts,basePackageName)
}
@CompileDynamic
private Set<Map.Entry<Path,List<ContractMetadata>>> inProgress(MultiValueMap<Path,ContractMetadata> contracts) {
return contracts.entrySet()
.findAll { Map.Entry<Path, List<ContractMetadata>> entry -> entry.getValue().any { it.anyInProgress() }}
}
@PackageScope
@CompileDynamic
Set<Map.Entry<Path,List<ContractMetadata>>> processAllNotInProgress(MultiValueMap<Path,ContractMetadata> contracts, String basePackageName) {
contracts.entrySet()
.findAll { Map.Entry<Path, List<ContractMetadata>> entry -> !entry.value.any { it.anyInProgress() }}
.each {
Map.Entry<Path, List<ContractMetadata>> entry ->
processIncludedDirectory(
relativizeContractPath(entry), (Collection<ContractMetadata>) entry.
getValue(), basePackageName)
}
}
private String relativizeContractPath(Map.Entry<Path, List<ContractMetadata>> entry) {
Path relativePath = configProperties.contractsDslDir.toPath().
relativize(entry.getKey())
if (StringUtils.isEmpty(relativePath.toString())) {
return DEFAULT_CLASS_PREFIX
}
return relativePath.toString()
}
private void processIncludedDirectory(
final String includedDirectoryRelativePath, Collection<ContractMetadata> contracts, final String basePackageNameForClass) {
if (log.isDebugEnabled()) {
log.debug("Collected contracts with metadata ${contracts} relative path is [${includedDirectoryRelativePath}]")
}
if (contracts.size()) {
def className = afterLast(includedDirectoryRelativePath.toString(), File.separator) + resolveNameSuffix()
def convertedClassName = convertIllegalPackageChars(className)
def packageName =
buildPackage(basePackageNameForClass, includedDirectoryRelativePath)
Path dir = saver.generateTestBaseDir(basePackageNameForClass,
convertIllegalPackageChars(includedDirectoryRelativePath.toString()))
Path classPath = saver.pathToClass(dir, convertedClassName)
def classBytes = generator.
buildClass(configProperties, contracts, includedDirectoryRelativePath,
new SingleTestGenerator.GeneratedClassData(convertedClassName, packageName, classPath)).
getBytes(StandardCharsets.UTF_8)
saver.saveClassFile(classPath, classBytes)
counter.incrementAndGet()
}
}
private String resolveNameSuffix() {
return configProperties.nameSuffixForTests ?: configProperties.testFramework.classNameSuffix
}
protected static String buildPackage(final String packageNameForClass, final String includedDirectoryRelativePath) {
String directory = beforeLast(includedDirectoryRelativePath, File.separator)
String convertedPackage = "$packageNameForClass.${directoryToPackage(convertIllegalPackageChars(directory))}"
return !directory.empty ? convertedPackage : packageNameForClass
}
}

View File

@@ -1,254 +0,0 @@
/*
* Copyright 2013-2020 the original author or authors.
*
* 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
*
* https://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.springframework.cloud.contract.verifier.builder
import groovy.transform.CompileStatic
import groovy.transform.PackageScope
/**
* Builds a block of code. Allows to start, end, indent etc. pieces of code.
*
* @author Jakub Kubrynski, codearte.io
*
* @since 1.0.0
*/
@CompileStatic
class BlockBuilder {
private final StringBuilder builder
private final String spacer
private int indents
private String lineEnding = ""
private String labelPrefix = ""
/**
* @param spacer - char used for spacing
*/
BlockBuilder(String spacer) {
this.spacer = spacer
builder = new StringBuilder()
}
/**
* Setup line ending
*/
BlockBuilder setupLineEnding(String lineEnding) {
this.lineEnding = lineEnding
return this
}
/**
* Setup label prefix
*/
BlockBuilder setupLabelPrefix(String labelPrefix) {
this.labelPrefix = labelPrefix
return this
}
String getLineEnding() {
return this.lineEnding
}
/**
* Adds indents to start a new block
*/
BlockBuilder appendWithLabelPrefix(String label) {
return append(this.labelPrefix).append(label)
}
/**
* Adds indents to start a new block
*/
BlockBuilder startBlock() {
indents++
return this
}
/**
* Ends block by removing indents
*/
BlockBuilder endBlock() {
indents--
return this
}
/**
* Creates a block and adds indents
*/
BlockBuilder indent() {
startBlock().startBlock()
return this
}
/**
* Removes indents and closes the block
*/
BlockBuilder unindent() {
endBlock().endBlock()
return this
}
BlockBuilder addLine(String line) {
return addIndented(line).append("\n")
}
BlockBuilder addIndented(String line) {
return addIndentation().append(line)
}
BlockBuilder addIndented(Runnable runnable) {
addIndentation()
runnable.run()
return this
}
BlockBuilder addLineWithEnding(String line) {
addIndentation()
append(line).addEndingIfNotPresent().addEmptyLine()
return this
}
BlockBuilder addEndingIfNotPresent() {
addAtTheEnd(lineEnding)
return this
}
BlockBuilder addEmptyLine() {
builder << '\n'
return this
}
BlockBuilder appendWithSpace(String text) {
return addAtTheEnd(" ").append(text)
}
BlockBuilder appendWithSpace(Runnable runnable) {
addAtTheEnd(" ")
runnable.run()
return this
}
// synactic sugar
BlockBuilder append(Runnable runnable) {
runnable.run()
return this
}
BlockBuilder append(String string) {
builder << string
return this
}
BlockBuilder addIndentation() {
indents.times {
builder << spacer
}
return this
}
@PackageScope
BlockBuilder inBraces(Runnable runnable) {
builder.append("{\n")
startBlock()
runnable.run()
endBlock()
addAtTheEnd('\n')
addLine("}")
return this
}
boolean endsWith(String text) {
return builder.toString().endsWith(text)
}
BlockBuilder addAtTheEndIfEndsWithAChar(String toAdd) {
char lastChar = builder.charAt(builder.length() - 1)
if (Character.isLetter(lastChar)) {
builder.append(toAdd)
}
return this
}
/**
* Adds the given text at the end of the line
*
* @return updated BlockBuilder
*/
BlockBuilder addAtTheEnd(String toAdd) {
String lastChar = builder.charAt(builder.length() - 1) as String
String secondLastChar = builder.length() >= 2 ? builder.
charAt(builder.length() - 2) as String : ""
boolean isEndWithNewLine = endsWithNewLine(lastChar)
boolean lastCharSpecial = aSpecialSign(lastChar, toAdd)
boolean secondLastCharSpecial = aSpecialSign(secondLastChar, toAdd)
boolean lineEndingToAdd = toAdd == lineEnding
// lastChar = [;] , toAdd = [;]
if (lastChar == toAdd) {
return this
}
// secondLastChar = [ ], lastChar = [{] , toAdd = [;]
else if ((!isEndWithNewLine && lastCharSpecial) && lineEndingToAdd) {
return this
}
// secondLastChar = [{], lastChar = [\n] , toAdd = [;]
else if (isEndWithNewLine && secondLastCharSpecial) {
return this
}
else if (isEndWithNewLine && !secondLastCharSpecial) {
builder.replace(builder.length() - 1, builder.length(), toAdd)
builder << '\n'
}
else {
builder << toAdd
}
return this
}
private boolean endsWithNewLine(String character) {
return character as String == '\n'
}
private boolean aSpecialSign(String character, String toAdd) {
if (!character) {
return false
}
return character == "{" ||
(character == spacer && toAdd == spacer) ||
(character == spacer && toAdd == " ") ||
character == toAdd ||
(endsWithNewLine(character) &&
(toAdd == '\n' || toAdd == " " || toAdd == lineEnding))
}
/**
* Updates the current text with the provided one
*
* @param contents - text to replace the current content with
* @return updated Block Builder
*/
BlockBuilder updateContents(String contents) {
this.builder.replace(0, this.builder.length(), contents)
return this
}
@Override
String toString() {
return builder.toString()
}
}

View File

@@ -1,85 +0,0 @@
/*
* Copyright 2013-2020 the original author or authors.
*
* 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
*
* https://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.springframework.cloud.contract.verifier.builder.imports
import groovy.transform.CompileStatic
import org.springframework.cloud.contract.verifier.config.TestFramework
import static org.springframework.cloud.contract.verifier.config.TestFramework.CUSTOM
import static org.springframework.cloud.contract.verifier.config.TestFramework.JUNIT
import static org.springframework.cloud.contract.verifier.config.TestFramework.JUNIT5
import static org.springframework.cloud.contract.verifier.config.TestFramework.SPOCK
import static org.springframework.cloud.contract.verifier.config.TestFramework.TESTNG
/**
* Provides imports based on test framework.
*
* @author Olga Maciaszek-Sharma
*
* @since 2.1.0
* @deprecated
*/
@CompileStatic
@Deprecated
class BaseImportProvider {
private static final ImportDefinitions GENERAL_IMPORTS = new ImportDefinitions([], [
'org.springframework.cloud.contract.verifier.assertion.SpringCloudContractAssertions.assertThat',
'org.springframework.cloud.contract.verifier.util.ContractVerifierUtil.*'
])
private static
final Map<TestFramework, ImportDefinitions> TEST_FRAMEWORK_SPECIFIC_IMPORTS = [
(JUNIT) : new ImportDefinitions(['org.junit.Test']),
(JUNIT5): new ImportDefinitions(['org.junit.jupiter.api.Test']),
(SPOCK) : new ImportDefinitions([]),
(TESTNG): new ImportDefinitions(['org.testng.annotations.Test']),
(CUSTOM): new ImportDefinitions([])]
private static final Map<TestFramework, String> RULE_IMPORT = [
(JUNIT) : 'org.junit.Rule',
(JUNIT5): 'org.junit.jupiter.api.extension.ExtendWith',
(SPOCK) : 'org.junit.Rule',
(TESTNG): 'org.junit.Rule',
(CUSTOM): 'org.junit.Rule'
]
/**
* Returns list of imports for provided test framework.
* @param testFramework
* @return list of imports
*/
static List<String> getImports(TestFramework testFramework) {
return GENERAL_IMPORTS.imports +
TEST_FRAMEWORK_SPECIFIC_IMPORTS.get(testFramework).imports
}
/**
* @param testFramework test framework to pick the static imports for
* @return list of static imports for provided test framework.
*/
static List<String> getStaticImports(TestFramework testFramework) {
return GENERAL_IMPORTS.staticImports +
TEST_FRAMEWORK_SPECIFIC_IMPORTS.get(testFramework).staticImports
}
static String getRuleImport(TestFramework testFramework) {
return RULE_IMPORT.get(testFramework)
}
}

View File

@@ -1,113 +0,0 @@
/*
* Copyright 2013-2020 the original author or authors.
*
* 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
*
* https://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.springframework.cloud.contract.verifier.builder.imports
import org.springframework.cloud.contract.verifier.config.TestFramework
import org.springframework.cloud.contract.verifier.config.TestMode
import static org.springframework.cloud.contract.verifier.config.TestFramework.CUSTOM
import static org.springframework.cloud.contract.verifier.config.TestFramework.JUNIT
import static org.springframework.cloud.contract.verifier.config.TestFramework.JUNIT5
import static org.springframework.cloud.contract.verifier.config.TestFramework.SPOCK
import static org.springframework.cloud.contract.verifier.config.TestFramework.TESTNG
import static org.springframework.cloud.contract.verifier.config.TestMode.EXPLICIT
import static org.springframework.cloud.contract.verifier.config.TestMode.JAXRSCLIENT
import static org.springframework.cloud.contract.verifier.config.TestMode.MOCKMVC
import static org.springframework.cloud.contract.verifier.config.TestMode.WEBTESTCLIENT
/**
* Provides imports based on test framework and test mode.
*
* @author Olga Maciaszek-Sharma
*
* @since 2.1.0
*/
@Deprecated
class HttpImportProvider {
private final Map<TestMode, ImportDefinitions> TEST_MODE_SPECIFIC_IMPORTS = [
(JAXRSCLIENT) : new ImportDefinitions([], ['javax.ws.rs.client.Entity.*']),
(MOCKMVC) : new ImportDefinitions([], ["${restAssuredPackage}.module.mockmvc.RestAssuredMockMvc.*"]),
(EXPLICIT) : new ImportDefinitions([], ["${restAssuredPackage}.RestAssured.*"]),
(WEBTESTCLIENT): new ImportDefinitions([], ['io.restassured.module.webtestclient.RestAssuredWebTestClient.*'])]
private final Map<Tuple2<TestFramework, TestMode>, ImportDefinitions> FRAMEWORK_AND_TEST_MODE_SPECIFIC_IMPORTS = [
(new Tuple2(JUNIT, JAXRSCLIENT)) : new ImportDefinitions(['javax.ws.rs.core.Response']),
(new Tuple2(JUNIT5, JAXRSCLIENT)) : new ImportDefinitions(['javax.ws.rs.core.Response']),
(new Tuple2(TESTNG, JAXRSCLIENT)) : new ImportDefinitions(['javax.ws.rs.core.Response']),
(new Tuple2(JUNIT, MOCKMVC)) : new ImportDefinitions([
"${restAssuredPackage}.module.mockmvc.specification.MockMvcRequestSpecification",
"${restAssuredPackage}.response.ResponseOptions"]),
(new Tuple2(JUNIT, WEBTESTCLIENT)) : new ImportDefinitions([
'io.restassured.module.webtestclient.specification.WebTestClientRequestSpecification',
'io.restassured.module.webtestclient.response.WebTestClientResponse']),
(new Tuple2(JUNIT5, MOCKMVC)) : new ImportDefinitions([
"${restAssuredPackage}.module.mockmvc.specification.MockMvcRequestSpecification",
"${restAssuredPackage}.response.ResponseOptions"]),
(new Tuple2(JUNIT5, WEBTESTCLIENT)): new ImportDefinitions([
'io.restassured.module.webtestclient.specification.WebTestClientRequestSpecification',
'io.restassured.module.webtestclient.response.WebTestClientResponse']),
(new Tuple2(TESTNG, MOCKMVC)) : new ImportDefinitions([
"${restAssuredPackage}.module.mockmvc.specification.MockMvcRequestSpecification",
"${restAssuredPackage}.response.ResponseOptions"]),
(new Tuple2(TESTNG, WEBTESTCLIENT)): new ImportDefinitions([
'io.restassured.module.webtestclient.specification.WebTestClientRequestSpecification',
'io.restassured.module.webtestclient.response.WebTestClientResponse']),
(new Tuple2(JUNIT, EXPLICIT)) : new ImportDefinitions(["${restAssuredPackage}.specification.RequestSpecification",
"${restAssuredPackage}.response.Response"]),
(new Tuple2(JUNIT5, EXPLICIT)) : new ImportDefinitions(["${restAssuredPackage}.specification.RequestSpecification",
"${restAssuredPackage}.response.Response"]),
(new Tuple2(TESTNG, EXPLICIT)) : new ImportDefinitions(["${restAssuredPackage}.specification.RequestSpecification",
"${restAssuredPackage}.response.Response"]),
(new Tuple2(SPOCK, JAXRSCLIENT)) : new ImportDefinitions([]),
(new Tuple2(CUSTOM, JAXRSCLIENT)) : new ImportDefinitions([]),
(new Tuple2(SPOCK, MOCKMVC)) : new ImportDefinitions([]),
(new Tuple2(CUSTOM, MOCKMVC)) : new ImportDefinitions([]),
(new Tuple2(SPOCK, EXPLICIT)) : new ImportDefinitions([]),
(new Tuple2(CUSTOM, EXPLICIT)) : new ImportDefinitions([]),
(new Tuple2(SPOCK, WEBTESTCLIENT)) : new ImportDefinitions([]),
(new Tuple2(CUSTOM, WEBTESTCLIENT)): new ImportDefinitions([])
]
private final String restAssuredPackage
HttpImportProvider(String restAssuredPackage) {
this.restAssuredPackage = restAssuredPackage
}
/**
* Returns list of imports for http test contracts for provided test framework and test mode.
* @param testFramework
* @param testMode
* @return list of imports
*/
List<String> getImports(TestFramework testFramework, TestMode testMode) {
return TEST_MODE_SPECIFIC_IMPORTS.get(testMode).imports +
FRAMEWORK_AND_TEST_MODE_SPECIFIC_IMPORTS.get(new Tuple2(testFramework, testMode)).imports
}
/**
* Returns list of static imports for http test contracts for provided test framework and test mode.
* @param testFramework
* @param testMode
* @return list of static imports
*/
List<String> getStaticImports(TestFramework testFramework, TestMode testMode) {
return TEST_MODE_SPECIFIC_IMPORTS.get(testMode).staticImports +
FRAMEWORK_AND_TEST_MODE_SPECIFIC_IMPORTS.get(new Tuple2(testFramework, testMode)).staticImports
}
}

View File

@@ -1,85 +0,0 @@
/*
* Copyright 2013-2020 the original author or authors.
*
* 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
*
* https://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.springframework.cloud.contract.verifier.config.framework
import groovy.transform.CompileStatic
/**
* Defines elements characteristic of TestNG test framework to be used during test class construction.
*
* @author André Hoffmann
*
* @since 2.2.0
*/
@CompileStatic
class TestNGDefinition implements TestFrameworkDefinition {
@Override
String getClassModifier() {
return 'public '
}
@Override
String getMethodModifier() {
return 'public void '
}
@Override
String getLineSuffix() {
return ';'
}
@Override
String getClassExtension() {
'.java'
}
@Override
String getClassNameSuffix() {
return 'Test'
}
@Override
String getIgnoreClass() {
throw new UnsupportedOperationException('There is no @Ignore annotation for TestNG. A test can be disabled directly in the @Test annotation')
}
@Override
List<String> getOrderAnnotationImports() {
throw new UnsupportedOperationException('Not implemented yet in TestNG')
}
@Override
String getOrderAnnotation() {
throw new UnsupportedOperationException('Not implemented yet in TestNG')
}
@Override
String getIgnoreAnnotation() {
throw new UnsupportedOperationException('There is no @Ignore annotation for TestNG. A test can be disabled directly in the @Test annotation')
}
@Override
boolean annotationLevelRules() {
return false
}
@Override
String getRuleAnnotation(String annotationValue) {
throw new UnsupportedOperationException('Not available in TestNG.')
}
}

View File

@@ -1,258 +0,0 @@
/*
* Copyright 2013-2020 the original author or authors.
*
* 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
*
* https://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.springframework.cloud.contract.verifier.template
import java.util.regex.Matcher
import java.util.regex.Pattern
import com.github.tomakehurst.wiremock.extension.responsetemplating.helpers.WireMockHelpers
import groovy.transform.CompileStatic
import wiremock.com.github.jknack.handlebars.Handlebars
import wiremock.com.github.jknack.handlebars.Template
import org.springframework.cloud.contract.spec.ContractTemplate
import org.springframework.cloud.contract.spec.internal.CompositeContractTemplate
import org.springframework.cloud.contract.spec.internal.Request
import org.springframework.cloud.contract.verifier.builder.TestSideRequestTemplateModel
import org.springframework.cloud.contract.verifier.builder.handlebars.HandlebarsJsonPathHelper
/**
* Default Handlebars template processor
*
* @author Marcin Grzejszczak
* @since 1.1.0
*/
@CompileStatic
class HandlebarsTemplateProcessor implements TemplateProcessor, ContractTemplate {
private static final Pattern ESCAPED_LEGACY_JSON_PATH_PATTERN = Pattern.
compile("^.*\\{\\{\\{jsonpath this '(.*)'}}}.*\$")
private static final Pattern ESCAPED_JSON_PATH_PATTERN = Pattern.
compile("^.*\\{\\{\\{jsonPath request.body '(.*)'}}}.*\$")
private static final Pattern LEGACY_JSON_PATH_PATTERN = Pattern.
compile("^.*\\{\\{jsonpath this '(.*)'}}.*\$")
private static final Pattern JSON_PATH_PATTERN = Pattern.
compile("^.*\\{\\{jsonPath request.body '(.*)'}}.*\$")
private static final List<Pattern> PATTERNS = [ESCAPED_LEGACY_JSON_PATH_PATTERN,
ESCAPED_JSON_PATH_PATTERN, LEGACY_JSON_PATH_PATTERN, JSON_PATH_PATTERN]
private static final String LEGACY_JSON_PATH_TEMPLATE_NAME = HandlebarsJsonPathHelper.NAME
private static final String JSON_PATH_TEMPLATE_NAME = WireMockHelpers.jsonPath.name()
final ContractTemplate contractTemplate = new CompositeContractTemplate()
@Override
String transform(Request request, String testContents) {
TestSideRequestTemplateModel templateModel = TestSideRequestTemplateModel.
from(request)
Map<String, TestSideRequestTemplateModel> model = [(HandlebarsJsonPathHelper.REQUEST_MODEL_NAME): templateModel]
Template bodyTemplate = uncheckedCompileTemplate(testContents)
return templatedResponseBody(model, bodyTemplate)
}
@Override
boolean containsTemplateEntry(String line) {
return (line.contains(contractTemplate.openingTemplate())
&& line.contains(contractTemplate.closingTemplate())) ||
(line.contains(contractTemplate.escapedOpeningTemplate()) &&
line.contains(contractTemplate.escapedClosingTemplate()))
}
@Override
boolean containsJsonPathTemplateEntry(String line) {
return line.contains(openingTemplate() + LEGACY_JSON_PATH_TEMPLATE_NAME) ||
line.contains(openingTemplate() + JSON_PATH_TEMPLATE_NAME) ||
line.contains(escapedOpeningTemplate() + LEGACY_JSON_PATH_TEMPLATE_NAME) ||
line.contains(escapedOpeningTemplate() + JSON_PATH_TEMPLATE_NAME)
}
@Override
String jsonPathFromTemplateEntry(String line) {
if (!containsJsonPathTemplateEntry(line)) {
return ""
}
for (Pattern pattern : PATTERNS) {
Matcher matcher = pattern.matcher(line)
if (matcher.matches()) {
return matcher.group(1)
}
}
return ""
}
private String templatedResponseBody(Map<String, TestSideRequestTemplateModel> model, Template bodyTemplate) {
return uncheckedApplyTemplate(bodyTemplate, model)
}
private String uncheckedApplyTemplate(Template template, Object context) {
try {
return template.apply(context)
}
catch (IOException e) {
throw new RuntimeException(e)
}
}
private Template uncheckedCompileTemplate(String content) {
try {
Handlebars handlebars = new Handlebars()
handlebars.
registerHelper(HandlebarsJsonPathHelper.NAME, new HandlebarsJsonPathHelper())
handlebars.registerHelper(WireMockHelpers.jsonPath.
name(), new HandlebarsJsonPathHelper())
WireMockHelpers.values()
.findAll { it != WireMockHelpers.jsonPath }
.each { WireMockHelpers helper ->
handlebars.registerHelper(helper.name(), helper)
}
return handlebars.compileInline(content)
}
catch (IOException e) {
throw new RuntimeException(e)
}
}
@Override
boolean startsWithTemplate(String text) {
return this.contractTemplate.startsWithTemplate(text)
}
@Override
boolean startsWithEscapedTemplate(String text) {
return this.contractTemplate.startsWithEscapedTemplate(text)
}
@Override
String openingTemplate() {
return this.contractTemplate.openingTemplate()
}
@Override
String closingTemplate() {
return this.contractTemplate.closingTemplate()
}
@Override
String escapedOpeningTemplate() {
return this.contractTemplate.escapedOpeningTemplate()
}
@Override
String escapedClosingTemplate() {
return this.contractTemplate.escapedClosingTemplate()
}
@Override
String url() {
return this.contractTemplate.url()
}
@Override
String query(String key) {
return this.contractTemplate.query(key)
}
@Override
String query(String key, int index) {
return this.contractTemplate.query(key, index)
}
@Override
String path() {
return this.contractTemplate.path()
}
@Override
String path(int index) {
return this.contractTemplate.path(index)
}
@Override
String header(String key) {
return this.contractTemplate.header(key)
}
@Override
String header(String key, int index) {
return this.contractTemplate.header(key, index)
}
@Override
String cookie(String key) {
return this.contractTemplate.cookie(key)
}
@Override
String body() {
return this.contractTemplate.body()
}
@Override
String body(String jsonPath) {
return this.contractTemplate.body(jsonPath)
}
@Override
String escapedUrl() {
return this.contractTemplate.escapedUrl()
}
@Override
String escapedQuery(String key) {
return this.contractTemplate.escapedQuery(key)
}
@Override
String escapedQuery(String key, int index) {
return this.contractTemplate.escapedQuery(key, index)
}
@Override
String escapedPath() {
return this.contractTemplate.escapedPath()
}
@Override
String escapedPath(int index) {
return this.contractTemplate.escapedPath(index)
}
@Override
String escapedHeader(String key) {
return this.contractTemplate.escapedHeader(key)
}
@Override
String escapedHeader(String key, int index) {
return this.contractTemplate.escapedHeader(key, index)
}
@Override
String escapedCookie(String key) {
return this.contractTemplate.escapedCookie(key)
}
@Override
String escapedBody() {
return this.contractTemplate.escapedBody()
}
@Override
String escapedBody(String jsonPath) {
return this.contractTemplate.escapedBody(jsonPath)
}
}

View File

@@ -1,107 +0,0 @@
/*
* Copyright 2013-2020 the original author or authors.
*
* 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
*
* https://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.springframework.cloud.contract.verifier.util
import java.nio.file.Files
import groovy.transform.CompileStatic
import org.apache.commons.logging.Log
import org.apache.commons.logging.LogFactory
import org.springframework.cloud.contract.spec.Contract
import org.springframework.cloud.contract.spec.ContractConverter
/**
* Allows conversion of Contract files to files.
*
* WARNING: This class is incubating and experimental. It might change in the future.
*
* @author Marcin Grzejszczak
* @since 2.1.0
*/
@CompileStatic
final class ToFileContractsTransformer {
private static final Log log = LogFactory.getLog(ToFileContractsTransformer.class)
/**
* Dumps contracts as files for the given {@link ContractConverter}
*
* - argument 1 : FQN - fully qualified name of the {@link ContractConverter} [REQUIRED]
* - argument 2 : path - path where the dumped files should be stored [OPTIONAL - defaults to target/converted-contracts]
* - argument 3 : path - path were the contracts should be searched for [OPTIONAL - defaults to src/test/resources/contracts]
*/
static void main(String[] args) {
if (args.length == 0) {
throw new IllegalStateException(exceptionMessage())
}
log.warn("You're using an incubating feature. Note, that it can be changed / removed in the future")
String fqn = args[0]
String outputPath = args.length >= 2 ? args[1] : "target/converted-contracts"
String path = args.length >= 3 ? args[2] : "src/test/resources/contracts"
new ToFileContractsTransformer().storeContractsAsFiles(path, fqn, outputPath)
}
private static String exceptionMessage() {
return "Please provide the FQN of the ContractConverter. E.g. [org.springframework.cloud.contract.verifier.converter.YamlContractConverter]"
}
/**
*
* @param path - path were the contracts should be searched for
* @param fqn - fully qualified name of the {@link ContractConverter}
* @param outputPath - path where the dumped files should be stored
* @return list of dumped files
*/
final List<File> storeContractsAsFiles(String path, String fqn, String outputPath) {
try {
log.info("Input path [" + path + "]")
log.info("FQN of the converter [" + fqn + "]")
log.info("Output path [" + outputPath + "]")
Collection<Contract> contracts = ContractScanner.
collectContractDescriptors(new File(path))
log.info("Found [" + contracts.size() + "] contract definition")
Class<?> name = Class.forName(fqn)
ContractConverter<Collection> contractConverter = (ContractConverter) name.
newInstance()
Collection converted = contractConverter.convertTo(contracts)
log.info("Successfully converted contracts definitions")
Map<String, byte[]> stored = contractConverter.store(converted)
File outputFolder = new File(outputPath)
outputFolder.mkdirs()
int i = 1
Set<Map.Entry<String, byte[]>> entries = stored.entrySet()
log.info("Will convert [" + entries.size() + "] contracts")
List<File> files = new ArrayList<>()
for (Map.Entry<String, byte[]> entry : entries) {
File outputFile = new File(outputFolder, entry.getKey())
Files.write(outputFile.toPath(), entry.getValue())
log.info("[" + i + "/"
+ entries.
size()
+ "] Successfully stored ["
+ outputFile.getName()
+ "]")
files.add(outputFile)
}
return files
}
catch (Exception ex) {
throw new IllegalStateException(ex)
}
}
}

View File

@@ -0,0 +1,75 @@
/*
* Copyright 2013-2020 the original author or authors.
*
* 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
*
* https://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.springframework.cloud.contract.verifier;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import static java.nio.file.StandardOpenOption.CREATE;
import static java.nio.file.StandardOpenOption.TRUNCATE_EXISTING;
import static org.springframework.cloud.contract.verifier.util.NamesUtil.beforeLast;
import static org.springframework.cloud.contract.verifier.util.NamesUtil.capitalize;
import static org.springframework.cloud.contract.verifier.util.NamesUtil.packageToDirectory;
class FileSaver {
private static final Logger log = LoggerFactory.getLogger(FileSaver.class);
private final File targetDirectory;
private final String fileExtension;
FileSaver(File targetDirectory, String fileExtension) {
this.targetDirectory = targetDirectory;
this.fileExtension = fileExtension;
}
public void saveClassFile(Path classPath, byte[] classBytes) {
log.info("Creating new class file [{}]", classPath);
try {
Files.write(classPath, classBytes, CREATE, TRUNCATE_EXISTING);
}
catch (IOException e) {
throw new RuntimeException(e);
}
}
protected Path pathToClass(Path testBaseDir, String fileName) {
return Paths.get(testBaseDir.toString(), capitalize(fileName) + fileExtension)
.toAbsolutePath();
}
protected Path generateTestBaseDir(String basePackageClass,
String includedDirectoryRelativePath) {
Path testBaseDir = Paths.get(targetDirectory.getAbsolutePath(),
packageToDirectory(basePackageClass),
beforeLast(includedDirectoryRelativePath, File.separator));
try {
Files.createDirectories(testBaseDir);
}
catch (IOException e) {
throw new RuntimeException(e);
}
return testBaseDir;
}
}

View File

@@ -0,0 +1,208 @@
/*
* Copyright 2013-2020 the original author or authors.
*
* 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
*
* https://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.springframework.cloud.contract.verifier;
import java.io.File;
import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cloud.contract.spec.ContractVerifierException;
import org.springframework.cloud.contract.verifier.builder.JavaTestGenerator;
import org.springframework.cloud.contract.verifier.builder.SingleTestGenerator;
import org.springframework.cloud.contract.verifier.config.ContractVerifierConfigProperties;
import org.springframework.cloud.contract.verifier.file.ContractFileScanner;
import org.springframework.cloud.contract.verifier.file.ContractFileScannerBuilder;
import org.springframework.cloud.contract.verifier.file.ContractMetadata;
import org.springframework.core.io.support.SpringFactoriesLoader;
import org.springframework.util.MultiValueMap;
import static org.springframework.cloud.contract.verifier.util.NamesUtil.afterLast;
import static org.springframework.cloud.contract.verifier.util.NamesUtil.beforeLast;
import static org.springframework.cloud.contract.verifier.util.NamesUtil.convertIllegalPackageChars;
import static org.springframework.cloud.contract.verifier.util.NamesUtil.directoryToPackage;
import static org.springframework.cloud.contract.verifier.util.NamesUtil.recrusiveDirectoryToPackage;
import static org.springframework.cloud.contract.verifier.util.NamesUtil.toLastDot;
/**
* @author Jakub Kubrynski, codearte.io
*/
public class TestGenerator {
private static final Logger log = LoggerFactory.getLogger(TestGenerator.class);
private static final String DEFAULT_CLASS_PREFIX = "ContractVerifier";
private static final String DEFAULT_TEST_PACKAGE = "org.springframework.cloud.contract.verifier.tests";
private final ContractVerifierConfigProperties configProperties;
private final AtomicInteger counter = new AtomicInteger();
private final SingleTestGenerator generator;
private final FileSaver saver;
private final ContractFileScanner contractFileScanner;
public TestGenerator(ContractVerifierConfigProperties configProperties) {
this(configProperties, singleTestGenerator(),
new FileSaver(configProperties.getGeneratedTestSourcesDir(),
configProperties.getTestFramework().getClassExtension()));
}
private static SingleTestGenerator singleTestGenerator() {
List<SingleTestGenerator> factories = SpringFactoriesLoader
.loadFactories(SingleTestGenerator.class, null);
if (factories.isEmpty()) {
return new JavaTestGenerator();
}
return factories.get(0);
}
public TestGenerator(ContractVerifierConfigProperties configProperties,
SingleTestGenerator generator, FileSaver saver) {
this(configProperties, generator, saver,
new ContractFileScannerBuilder()
.baseDir(configProperties.getContractsDslDir())
.excluded(toSet(configProperties.getExcludedFiles()))
.ignored(toSet(configProperties.getIgnoredFiles()))
.included(toSet(configProperties.getIncludedFiles()))
.includeMatcher(configProperties.getIncludedContracts()).build());
}
private static Set<String> toSet(List<String> files) {
return Optional.ofNullable(files).map(HashSet::new).orElseGet(HashSet::new);
}
protected TestGenerator(ContractVerifierConfigProperties configProperties,
SingleTestGenerator generator, FileSaver saver,
ContractFileScanner contractFileScanner) {
this.configProperties = configProperties;
if (configProperties.getContractsDslDir() == null) {
throw new ContractVerifierException("Stubs directory not found under "
+ configProperties.getContractsDslDir());
}
this.generator = generator;
this.saver = saver;
this.contractFileScanner = contractFileScanner;
}
public int generate() {
generateTestClasses(basePackageName());
recrusiveDirectoryToPackage(configProperties.getGeneratedTestSourcesDir());
recrusiveDirectoryToPackage(configProperties.getGeneratedTestResourcesDir());
return counter.get();
}
private String basePackageName() {
if (StringUtils.isNotEmpty(configProperties.getBasePackageForTests())) {
return configProperties.getBasePackageForTests();
}
else if (StringUtils.isNotEmpty(configProperties.getBaseClassForTests())) {
return toLastDot(configProperties.getBaseClassForTests());
}
else if (StringUtils.isNotEmpty(configProperties.getPackageWithBaseClasses())) {
return configProperties.getPackageWithBaseClasses();
}
return DEFAULT_TEST_PACKAGE;
}
void generateTestClasses(final String basePackageName) {
MultiValueMap<Path, ContractMetadata> contracts = contractFileScanner
.findContractsRecursively();
log.debug("Found the following contracts {}", contracts.keySet());
Set<Map.Entry<Path, List<ContractMetadata>>> inProgress = inProgress(contracts);
if (!inProgress.isEmpty() && configProperties.isFailOnInProgress()) {
String inProgressContractsPaths = inProgress.stream().map(Map.Entry::getKey)
.map(Path::toString).collect(Collectors.joining(","));
throw new IllegalStateException("In progress contracts found in paths ["
+ inProgressContractsPaths
+ "] and the switch [failOnInProgress] is set to [true]. Either unmark those contracts as in progress, or set the switch to [false].");
}
processAllNotInProgress(contracts, basePackageName);
}
private Set<Map.Entry<Path, List<ContractMetadata>>> inProgress(
MultiValueMap<Path, ContractMetadata> contracts) {
return contracts.entrySet().stream()
.filter(entry -> entry.getValue().stream()
.anyMatch(ContractMetadata::anyInProgress))
.collect(Collectors.toSet());
}
void processAllNotInProgress(MultiValueMap<Path, ContractMetadata> contracts,
final String basePackageName) {
contracts.entrySet().stream()
.filter(entry -> entry.getValue().stream()
.noneMatch(ContractMetadata::anyInProgress))
.forEach(entry -> processIncludedDirectory(relativizeContractPath(entry),
entry.getValue(), basePackageName));
}
private String relativizeContractPath(Map.Entry<Path, List<ContractMetadata>> entry) {
Path relativePath = configProperties.getContractsDslDir().toPath()
.relativize(entry.getKey());
return StringUtils.defaultIfEmpty(relativePath.toString(), DEFAULT_CLASS_PREFIX);
}
private void processIncludedDirectory(final String includedDirectoryRelativePath,
final Collection<ContractMetadata> contracts,
final String basePackageNameForClass) {
log.debug("Collected contracts with metadata {} relative path is [{}]", contracts,
includedDirectoryRelativePath);
if (!contracts.isEmpty()) {
String className = afterLast(includedDirectoryRelativePath, File.separator)
+ resolveNameSuffix();
String convertedClassName = convertIllegalPackageChars(className);
String packageName = buildPackage(basePackageNameForClass,
includedDirectoryRelativePath);
Path dir = saver.generateTestBaseDir(basePackageNameForClass,
convertIllegalPackageChars(includedDirectoryRelativePath));
Path classPath = saver.pathToClass(dir, convertedClassName);
byte[] classBytes = generator
.buildClass(configProperties, contracts,
includedDirectoryRelativePath,
new SingleTestGenerator.GeneratedClassData(convertedClassName,
packageName, classPath))
.getBytes(StandardCharsets.UTF_8);
saver.saveClassFile(classPath, classBytes);
counter.incrementAndGet();
}
}
private String resolveNameSuffix() {
return StringUtils.defaultIfEmpty(configProperties.getNameSuffixForTests(),
configProperties.getTestFramework().getClassNameSuffix());
}
protected static String buildPackage(final String packageNameForClass,
final String includedDirectoryRelativePath) {
String directory = beforeLast(includedDirectoryRelativePath, File.separator);
String convertedPackage = packageNameForClass + "."
+ directoryToPackage(convertIllegalPackageChars(directory));
return !directory.isEmpty() ? convertedPackage : packageNameForClass;
}
}

View File

@@ -0,0 +1,248 @@
/*
* Copyright 2013-2020 the original author or authors.
*
* 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
*
* https://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.springframework.cloud.contract.verifier.builder;
import org.apache.commons.lang3.StringUtils;
/**
* Builds a block of code. Allows to start, end, indent etc. pieces of code.
*
* @author Jakub Kubrynski, codearte.io
* @since 1.0.0
*/
public class BlockBuilder {
private final StringBuilder builder;
private final String spacer;
private int indents;
private String lineEnding = "";
private String labelPrefix = "";
/**
* @param spacer - char used for spacing
*/
public BlockBuilder(String spacer) {
this.spacer = spacer;
builder = new StringBuilder();
}
/**
* Setup line ending
*/
public BlockBuilder setupLineEnding(String lineEnding) {
this.lineEnding = lineEnding;
return this;
}
/**
* Setup label prefix
*/
public BlockBuilder setupLabelPrefix(String labelPrefix) {
this.labelPrefix = labelPrefix;
return this;
}
public String getLineEnding() {
return this.lineEnding;
}
/**
* Adds indents to start a new block
*/
public BlockBuilder appendWithLabelPrefix(String label) {
return append(this.labelPrefix).append(label);
}
/**
* Adds indents to start a new block
*/
public BlockBuilder startBlock() {
indents++;
return this;
}
/**
* Ends block by removing indents
*/
public BlockBuilder endBlock() {
indents--;
return this;
}
/**
* Creates a block and adds indents
*/
public BlockBuilder indent() {
startBlock().startBlock();
return this;
}
/**
* Removes indents and closes the block
*/
public BlockBuilder unindent() {
endBlock().endBlock();
return this;
}
public BlockBuilder addLine(String line) {
return addIndented(line).append("\n");
}
public BlockBuilder addIndented(String line) {
return addIndentation().append(line);
}
public BlockBuilder addIndented(Runnable runnable) {
addIndentation();
runnable.run();
return this;
}
public BlockBuilder addLineWithEnding(String line) {
addIndentation();
append(line).addEndingIfNotPresent().addEmptyLine();
return this;
}
public BlockBuilder addEndingIfNotPresent() {
addAtTheEnd(lineEnding);
return this;
}
public BlockBuilder addEmptyLine() {
builder.append("\n");
return this;
}
public BlockBuilder appendWithSpace(String text) {
return addAtTheEnd(" ").append(text);
}
public BlockBuilder appendWithSpace(Runnable runnable) {
addAtTheEnd(" ");
runnable.run();
return this;
}
public BlockBuilder append(Runnable runnable) {
runnable.run();
return this;
}
public BlockBuilder append(String string) {
builder.append(string);
return this;
}
public BlockBuilder addIndentation() {
for (int i = 0; i < indents; i++) {
builder.append(spacer);
}
return this;
}
BlockBuilder inBraces(Runnable runnable) {
builder.append("{\n");
startBlock();
runnable.run();
endBlock();
addAtTheEnd("\n");
addLine("}");
return this;
}
public boolean endsWith(String text) {
return builder.toString().endsWith(text);
}
public BlockBuilder addAtTheEndIfEndsWithAChar(String toAdd) {
char lastChar = builder.charAt(builder.length() - 1);
if (Character.isLetter(lastChar)) {
builder.append(toAdd);
}
return this;
}
/**
* Adds the given text at the end of the line
* @return updated BlockBuilder
*/
public BlockBuilder addAtTheEnd(String toAdd) {
String lastChar = String.valueOf(builder.charAt(builder.length() - 1));
String secondLastChar = builder.length() >= 2
? String.valueOf(builder.charAt(builder.length() - 2)) : "";
boolean isEndWithNewLine = endsWithNewLine(lastChar);
boolean lastCharSpecial = aSpecialSign(lastChar, toAdd);
boolean secondLastCharSpecial = aSpecialSign(secondLastChar, toAdd);
boolean lineEndingToAdd = toAdd.equals(lineEnding);
// lastChar = [;] , toAdd = [;]
if (lastChar.equals(toAdd)) {
return this;
}
// secondLastChar = [ ], lastChar = [{] , toAdd = [;]
else if ((!isEndWithNewLine && lastCharSpecial) && lineEndingToAdd) {
return this;
}
// secondLastChar = [{], lastChar = [\n] , toAdd = [;]
else if (isEndWithNewLine && secondLastCharSpecial) {
return this;
}
else if (isEndWithNewLine && !secondLastCharSpecial) {
builder.replace(builder.length() - 1, builder.length(), toAdd);
builder.append("\n");
}
else {
builder.append(toAdd);
}
return this;
}
private boolean endsWithNewLine(String character) {
return character.equals("\n");
}
private boolean aSpecialSign(String character, String toAdd) {
if (StringUtils.isEmpty(character)) {
return false;
}
return character.equals("{") || (character.equals(spacer) && toAdd.equals(spacer))
|| (character.equals(spacer) && toAdd.equals(" "))
|| character.equals(toAdd) || (endsWithNewLine(character)
&& StringUtils.equalsAny(toAdd, "\n", " ", lineEnding));
}
/**
* Updates the current text with the provided one
* @param contents - text to replace the current content with
* @return updated Block Builder
*/
public BlockBuilder updateContents(String contents) {
this.builder.replace(0, this.builder.length(), contents);
return this;
}
@Override
public String toString() {
return builder.toString();
}
}

View File

@@ -20,7 +20,6 @@ import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import org.springframework.cloud.contract.spec.internal.Request;
import org.springframework.cloud.contract.verifier.file.SingleContractMetadata;
import org.springframework.cloud.contract.verifier.template.HandlebarsTemplateProcessor;
import org.springframework.cloud.contract.verifier.template.TemplateProcessor;

Some files were not shown because too many files have changed in this diff Show More