Fixed the way package and class names are generated

with the new layout of contracts and stubs the package name was improperly generated (for chars like +, or digits)
with this change we're converting those chars to _

fixes #276
This commit is contained in:
Marcin Grzejszczak
2017-04-28 12:46:45 +02:00
parent c22c47153e
commit 8ca2ed6b22
6 changed files with 84 additions and 27 deletions

View File

@@ -42,7 +42,6 @@ class FileSaver {
}
void saveClassFile(String fileName, String basePackageClass, String includedDirectoryRelativePath, byte[] classBytes) {
Path testBaseDir = Paths.get(targetDirectory.absolutePath, packageToDirectory(basePackageClass),
beforeLast(includedDirectoryRelativePath, File.separator))
Files.createDirectories(testBaseDir)

View File

@@ -87,9 +87,10 @@ class TestGenerator {
final String includedDirectoryRelativePath, Collection<ContractMetadata> contracts, final String basePackageNameForClass) {
if (contracts.size()) {
def className = afterLast(includedDirectoryRelativePath.toString(), File.separator) + resolveNameSuffix()
def convertedClassName = convertIllegalPackageChars(className)
def packageName = buildPackage(basePackageNameForClass, includedDirectoryRelativePath)
def classBytes = generator.buildClass(contracts, className, packageName, includedDirectoryRelativePath).getBytes(StandardCharsets.UTF_8)
saver.saveClassFile(className, basePackageNameForClass, convertIllegalPackageChars(includedDirectoryRelativePath.toString()), classBytes)
def classBytes = generator.buildClass(contracts, convertedClassName, packageName, includedDirectoryRelativePath).getBytes(StandardCharsets.UTF_8)
saver.saveClassFile(convertedClassName, basePackageNameForClass, convertIllegalPackageChars(includedDirectoryRelativePath.toString()), classBytes)
counter.incrementAndGet()
}
}
@@ -98,9 +99,10 @@ class TestGenerator {
return configProperties.nameSuffixForTests ?: configProperties.targetFramework.classNameSuffix
}
private static String buildPackage(final String packageNameForClass, final String includedDirectoryRelativePath) {
protected static String buildPackage(final String packageNameForClass, final String includedDirectoryRelativePath) {
String directory = beforeLast(includedDirectoryRelativePath, File.separator)
return !directory.empty ? "$packageNameForClass.${directoryToPackage(convertIllegalPackageChars(directory))}" : packageNameForClass
String convertedPackage = "$packageNameForClass.${directoryToPackage(convertIllegalPackageChars(directory))}"
return !directory.empty ? convertedPackage : packageNameForClass
}
}

View File

@@ -99,13 +99,16 @@ class NamesUtil {
* Converts the path format to a Java package notation
*/
static String directoryToPackage(String directory) {
return directory.replace(File.separator, '.')
return directory
.replace('.', '_')
.replace(File.separator, '.')
.replaceAll('\\.([0-9])', '._$1')
}
/**
* Converts illegal package characters to underscores
*/
static String convertIllegalPackageChars(String packageName) {
return packageName.replaceAll('[_\\- .]', '_')
return packageName.replaceAll('[_\\- .+]', '_')
}
}

View File

@@ -63,9 +63,9 @@ class ClassBuilderSpec extends Specification {
def "should return a class from the generated path by when external contracts are picked"() {
given:
ContractVerifierConfigProperties props = new ContractVerifierConfigProperties(packageWithBaseClasses: "foo.Bar")
String contractRelativeFolder = ["org","springframework","cloud","contract","verifier","tests","META_INF","com.example","hello_world","1.0.0"].join(File.separator)
String contractRelativeFolder = ["org","springframework","cloud","contract","verifier","tests","META_INF","com.example","hello_world","0.1.0_dev.1.uncommitted+d1174dd"].join(File.separator)
expect:
ClassBuilder.retrieveBaseClass(props, contractRelativeFolder) == 'foo.Bar.Hello_world1_0_0Base'
ClassBuilder.retrieveBaseClass(props, contractRelativeFolder) == 'foo.Bar.Hello_world0_1_0_dev_1_uncommitted_d1174ddBase'
}
}

View File

@@ -18,6 +18,7 @@ package org.springframework.cloud.contract.verifier.builder
import org.junit.Rule
import org.junit.rules.TemporaryFolder
import org.springframework.cloud.contract.verifier.TestGenerator
import org.springframework.cloud.contract.verifier.config.ContractVerifierConfigProperties
import org.springframework.cloud.contract.verifier.config.TestMode
import org.springframework.cloud.contract.verifier.file.ContractMetadata
@@ -82,14 +83,26 @@ class SingleTestGeneratorSpec extends Specification {
public static final Closure JAVA_ASSERTER = { String classToTest ->
String name = Math.abs(new Random().nextInt())
String changedTest = classToTest.replace("public class Test", "public class Test${name}")
SyntaxChecker.tryToCompileJavaWithoutImports("test.Test${name}", changedTest)
String changedTest = classToTest
.replace("public class Test", "public class Test${name}")
.replace("public class ContractsTest", "public class Test${name}")
String fqn = FQN(classToTest)
SyntaxChecker.tryToCompileJavaWithoutImports("${fqn}${name}", changedTest)
}
static String FQN(String classToTest) {
return classToTest.contains("0_1_0_dev_1_uncommitted_d1174dd") ?
"org.springframework.cloud.contract.verifier.tests.com_uscm.dale_api44_spec._0_1_0_dev_1_uncommitted_d1174dd.Test" :
"test.Test"
}
public static final Closure JAVA_JAXRS_ASSERTER = { String classToTest ->
String name = Math.abs(new Random().nextInt())
String changedTest = classToTest.replace("public class Test {", "public class Test${name} {\njavax.ws.rs.client.WebTarget webTarget;\n")
SyntaxChecker.tryToCompileJavaWithoutImports("test.Test${name}", changedTest)
String changedTest = classToTest
.replace("public class Test {", "public class Test${name} {\njavax.ws.rs.client.WebTarget webTarget;\n")
.replace("public class ContractsTest {", "public class Test${name} {\njavax.ws.rs.client.WebTarget webTarget;\n")
String fqn = FQN(classToTest)
SyntaxChecker.tryToCompileJavaWithoutImports("${fqn}${name}", changedTest)
}
public static final Closure GROOVY_ASSERTER = { String classToTest ->
@@ -98,6 +111,10 @@ class SingleTestGeneratorSpec extends Specification {
def setup() {
file = tmpFolder.newFile()
wiriteContract(file)
}
private wiriteContract(File file) {
file.write("""
org.springframework.cloud.contract.spec.Contract.make {
request {
@@ -136,6 +153,33 @@ class SingleTestGeneratorSpec extends Specification {
SPOCK | TestMode.EXPLICIT | explicitSpockClassStrings | GROOVY_ASSERTER
}
def "should build test class for #testFramework when the path contains bizarre signs"() {
given:
ContractVerifierConfigProperties properties = new ContractVerifierConfigProperties()
properties.targetFramework = testFramework
properties.basePackageForTests = "org.springframework.cloud.contract.verifier.tests"
and:
File newFolder = tmpFolder.newFolder("META_INF")
File subfolders = new File(newFolder, "/com.uscm/dale_api44_spec/0.1.0_dev.1.uncommitted+d1174dd/contracts/")
subfolders.mkdirs()
File newFile = new File(subfolders, "contract.groovy")
newFile.createNewFile()
wiriteContract(newFile)
properties.contractsDslDir = newFolder
properties.generatedTestSourcesDir = newFolder.parentFile
when:
int size = new TestGenerator(properties).generate()
then:
size > 0
asserter(new File(newFolder.parent, "/org/springframework/cloud/contract/verifier/tests/com_uscm/dale_api44_spec/0_1_0_dev_1_uncommitted_d1174dd/${testName}").text)
where:
testFramework | mode | asserter | testName
JUNIT | TestMode.MOCKMVC | JAVA_ASSERTER | "ContractsTest.java"
JUNIT | TestMode.EXPLICIT | JAVA_ASSERTER | "ContractsTest.java"
SPOCK | TestMode.MOCKMVC | GROOVY_ASSERTER | "ContractsSpec.groovy"
SPOCK | TestMode.EXPLICIT | GROOVY_ASSERTER | "ContractsSpec.groovy"
}
def "should build test class for #testFramework with Rest Assured 3.0"() {
given:
ContractVerifierConfigProperties properties = new ContractVerifierConfigProperties()
@@ -406,4 +450,6 @@ class SingleTestGeneratorSpec extends Specification {
}
}

View File

@@ -11,90 +11,97 @@ class NamesUtilSpec extends Specification {
given:
String string = "a.b.c.d.e"
expect:
"a.b.c.d" == NamesUtil.beforeLast(string, ".")
NamesUtil.beforeLast(string, ".") == "a.b.c.d"
}
def "should return empty string when no token was found for before last"() {
given:
String string = "a.b.c.d.e"
expect:
"" == NamesUtil.beforeLast(string, "/")
NamesUtil.beforeLast(string, "/") == ""
}
def "should return first token after the last one"() {
given:
String string = "a.b.c.d.e"
expect:
"e" == NamesUtil.afterLast(string, ".")
NamesUtil.afterLast(string, ".") == "e"
}
def "should return the input string when no token was found for after last"() {
given:
String string = "a.b.c.d.e"
expect:
string == NamesUtil.afterLast(string, "/")
NamesUtil.afterLast(string, "/") == string
}
def "should return first token after the last dot"() {
given:
String string = "a.b.c.d.e"
expect:
"e" == NamesUtil.afterLastDot(string)
NamesUtil.afterLastDot(string) == "e"
}
def "should return the input string when no token was found for after last dot"() {
given:
String string = "abcde"
expect:
string == NamesUtil.afterLastDot(string)
NamesUtil.afterLastDot(string) == string
}
def "should return camel case version of a string"() {
given:
String string = "BlaBlaBla"
expect:
"blaBlaBla" == NamesUtil.camelCase(string)
NamesUtil.camelCase(string) == "blaBlaBla"
}
def "should return capitalized version of a string"() {
given:
String string = "blaBlaBla"
expect:
"BlaBlaBla" == NamesUtil.capitalize(string)
NamesUtil.capitalize(string) == "BlaBlaBla"
}
def "should return all text to last dot"() {
given:
String string = "a.b.c.d.e"
expect:
"a.b.c.d" == NamesUtil.toLastDot(string)
NamesUtil.toLastDot(string) == "a.b.c.d"
}
def "should return the input string when no token was found for to last dot"() {
given:
String string = "abcde"
expect:
string == NamesUtil.toLastDot(string)
NamesUtil.toLastDot(string) == string
}
def "should convert a package notation to directory"() {
given:
String string = "a.b.c.d.e"
expect:
"a/b/c/d/e".replace("/", File.separator) == NamesUtil.packageToDirectory(string)
NamesUtil.packageToDirectory(string) == "a/b/c/d/e".replace("/", File.separator)
}
def "should convert a directory notation to package"() {
given:
String string = "a/b/c/d/e".replace("/", File.separator)
expect:
"a.b.c.d.e" == NamesUtil.directoryToPackage(string)
NamesUtil.directoryToPackage(string) == "a.b.c.d.e"
}
def "should convert a directory notation to package when folder is a digit"() {
given:
String string = "a/b/c/1.0.0/e".replace("/", File.separator)
expect:
NamesUtil.directoryToPackage(string) == "a.b.c._1_0_0.e"
}
def "should convert all illegal package chars to legal ones"() {
given:
String string = "a-b c.1.0.x"
String string = "a-b c.1.0.x+d1174dd"
expect:
"a_b_c_1_0_x" == NamesUtil.convertIllegalPackageChars(string)
NamesUtil.convertIllegalPackageChars(string) == "a_b_c_1_0_x_d1174dd"
}
}