Added "touch" command to incremental tests and implemented; Implemented more accurate checking lookups after modifications
Original commit: 24037c8bf4
This commit is contained in:
@@ -69,6 +69,10 @@ public abstract class AbstractIncrementalJpsTest(
|
|||||||
val TEMP_DIRECTORY_TO_USE = File(FileUtilRt.getTempDirectory())
|
val TEMP_DIRECTORY_TO_USE = File(FileUtilRt.getTempDirectory())
|
||||||
|
|
||||||
val DEBUG_LOGGING_ENABLED = System.getProperty("debug.logging.enabled") == "true"
|
val DEBUG_LOGGING_ENABLED = System.getProperty("debug.logging.enabled") == "true"
|
||||||
|
|
||||||
|
private val COMMANDS = listOf("new", "touch", "delete")
|
||||||
|
private val COMMANDS_AS_REGEX_PART = COMMANDS.joinToString("|")
|
||||||
|
private val COMMANDS_AS_MESSAGE_PART = COMMANDS.joinToString("/") { "\".$it\"" }
|
||||||
}
|
}
|
||||||
|
|
||||||
protected var testDataDir: File by Delegates.notNull()
|
protected var testDataDir: File by Delegates.notNull()
|
||||||
@@ -77,6 +81,8 @@ public abstract class AbstractIncrementalJpsTest(
|
|||||||
|
|
||||||
protected var projectDescriptor: ProjectDescriptor by Delegates.notNull()
|
protected var projectDescriptor: ProjectDescriptor by Delegates.notNull()
|
||||||
|
|
||||||
|
protected val mapWorkingToOriginalFile: MutableMap<File, File> = hashMapOf()
|
||||||
|
|
||||||
private fun enableDebugLogging() {
|
private fun enableDebugLogging() {
|
||||||
com.intellij.openapi.diagnostic.Logger.setFactory(javaClass<TestLoggerFactory>())
|
com.intellij.openapi.diagnostic.Logger.setFactory(javaClass<TestLoggerFactory>())
|
||||||
TestLoggerFactory.dumpLogToStdout("")
|
TestLoggerFactory.dumpLogToStdout("")
|
||||||
@@ -108,10 +114,10 @@ public abstract class AbstractIncrementalJpsTest(
|
|||||||
|
|
||||||
protected open fun createLookupTracker(): LookupTracker = LookupTracker.DO_NOTHING
|
protected open fun createLookupTracker(): LookupTracker = LookupTracker.DO_NOTHING
|
||||||
|
|
||||||
protected open fun checkLookups(modifications: List<Modification>, @Suppress("UNUSED_PARAMETER") lookupTracker: LookupTracker) {
|
protected open fun checkLookups(@Suppress("UNUSED_PARAMETER") lookupTracker: LookupTracker, compiledFiles: Set<File>) {
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun build(scope: CompileScopeTestBuilder = CompileScopeTestBuilder.make().all(), modifications: List<Modification>, checkLookups: Boolean = true): MakeResult {
|
private fun build(scope: CompileScopeTestBuilder = CompileScopeTestBuilder.make().all(), checkLookups: Boolean = true): MakeResult {
|
||||||
val workDirPath = FileUtil.toSystemIndependentName(workDir.absolutePath)
|
val workDirPath = FileUtil.toSystemIndependentName(workDir.absolutePath)
|
||||||
val logger = MyLogger(workDirPath)
|
val logger = MyLogger(workDirPath)
|
||||||
projectDescriptor = createProjectDescriptor(BuildLoggingManager(logger))
|
projectDescriptor = createProjectDescriptor(BuildLoggingManager(logger))
|
||||||
@@ -127,7 +133,7 @@ public abstract class AbstractIncrementalJpsTest(
|
|||||||
builder.build(scope.build(), false)
|
builder.build(scope.build(), false)
|
||||||
|
|
||||||
if (checkLookups) {
|
if (checkLookups) {
|
||||||
checkLookups(modifications, lookupTracker)
|
checkLookups(lookupTracker, logger.compiledFiles)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!buildResult.isSuccessful) {
|
if (!buildResult.isSuccessful) {
|
||||||
@@ -150,7 +156,7 @@ public abstract class AbstractIncrementalJpsTest(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun initialMake(): MakeResult {
|
private fun initialMake(): MakeResult {
|
||||||
val makeResult = build(modifications = emptyList())
|
val makeResult = build()
|
||||||
|
|
||||||
val initBuildLogFile = File(testDataDir, "init-build.log")
|
val initBuildLogFile = File(testDataDir, "init-build.log")
|
||||||
if (initBuildLogFile.exists()) {
|
if (initBuildLogFile.exists()) {
|
||||||
@@ -163,17 +169,17 @@ public abstract class AbstractIncrementalJpsTest(
|
|||||||
return makeResult
|
return makeResult
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun make(modifications: List<Modification>): MakeResult {
|
private fun make(): MakeResult {
|
||||||
return build(modifications = modifications)
|
return build()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun rebuild(): MakeResult {
|
private fun rebuild(): MakeResult {
|
||||||
return build(CompileScopeTestBuilder.rebuild().allModules(), emptyList(), checkLookups = false)
|
return build(CompileScopeTestBuilder.rebuild().allModules(), checkLookups = false)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getModificationsToPerform(moduleNames: Collection<String>?): List<List<Modification>> {
|
private fun getModificationsToPerform(moduleNames: Collection<String>?): List<List<Modification>> {
|
||||||
|
|
||||||
fun getModificationsForIteration(newSuffix: String, deleteSuffix: String): List<Modification> {
|
fun getModificationsForIteration(newSuffix: String, touchSuffix: String, deleteSuffix: String): List<Modification> {
|
||||||
|
|
||||||
fun getDirPrefix(fileName: String): String {
|
fun getDirPrefix(fileName: String): String {
|
||||||
val underscore = fileName.indexOf("_")
|
val underscore = fileName.indexOf("_")
|
||||||
@@ -198,6 +204,9 @@ public abstract class AbstractIncrementalJpsTest(
|
|||||||
if (fileName.endsWith(newSuffix)) {
|
if (fileName.endsWith(newSuffix)) {
|
||||||
modifications.add(ModifyContent(getDirPrefix(fileName) + "/" + fileName.removeSuffix(newSuffix), file))
|
modifications.add(ModifyContent(getDirPrefix(fileName) + "/" + fileName.removeSuffix(newSuffix), file))
|
||||||
}
|
}
|
||||||
|
if (fileName.endsWith(touchSuffix)) {
|
||||||
|
modifications.add(TouchFile(getDirPrefix(fileName) + "/" + fileName.removeSuffix(touchSuffix)))
|
||||||
|
}
|
||||||
if (fileName.endsWith(deleteSuffix)) {
|
if (fileName.endsWith(deleteSuffix)) {
|
||||||
modifications.add(DeleteFile(getDirPrefix(fileName) + "/" + fileName.removeSuffix(deleteSuffix)))
|
modifications.add(DeleteFile(getDirPrefix(fileName) + "/" + fileName.removeSuffix(deleteSuffix)))
|
||||||
}
|
}
|
||||||
@@ -205,27 +214,27 @@ public abstract class AbstractIncrementalJpsTest(
|
|||||||
return modifications
|
return modifications
|
||||||
}
|
}
|
||||||
|
|
||||||
val haveFilesWithoutNumbers = testDataDir.listFiles { it.getName().matches(".+\\.(new|delete)$".toRegex()) }?.isNotEmpty() ?: false
|
val haveFilesWithoutNumbers = testDataDir.listFiles { it.getName().matches(".+\\.($COMMANDS_AS_REGEX_PART)$".toRegex()) }?.isNotEmpty() ?: false
|
||||||
val haveFilesWithNumbers = testDataDir.listFiles { it.getName().matches(".+\\.(new|delete)\\.\\d+$".toRegex()) }?.isNotEmpty() ?: false
|
val haveFilesWithNumbers = testDataDir.listFiles { it.getName().matches(".+\\.($COMMANDS_AS_REGEX_PART)\\.\\d+$".toRegex()) }?.isNotEmpty() ?: false
|
||||||
|
|
||||||
if (haveFilesWithoutNumbers && haveFilesWithNumbers) {
|
if (haveFilesWithoutNumbers && haveFilesWithNumbers) {
|
||||||
fail("Bad test data format: files ending with both unnumbered and numbered \".new\"/\".delete\" were found")
|
fail("Bad test data format: files ending with both unnumbered and numbered $COMMANDS_AS_MESSAGE_PART were found")
|
||||||
}
|
}
|
||||||
if (!haveFilesWithoutNumbers && !haveFilesWithNumbers) {
|
if (!haveFilesWithoutNumbers && !haveFilesWithNumbers) {
|
||||||
if (allowNoFilesWithSuffixInTestData) {
|
if (allowNoFilesWithSuffixInTestData) {
|
||||||
return listOf(listOf())
|
return listOf(listOf())
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
fail("Bad test data format: no files ending with \".new\" or \".delete\" found")
|
fail("Bad test data format: no files ending with $COMMANDS_AS_MESSAGE_PART found")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (haveFilesWithoutNumbers) {
|
if (haveFilesWithoutNumbers) {
|
||||||
return listOf(getModificationsForIteration(".new", ".delete"))
|
return listOf(getModificationsForIteration(".new", ".touch", ".delete"))
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return (1..10)
|
return (1..10)
|
||||||
.map { getModificationsForIteration(".new.$it", ".delete.$it") }
|
.map { getModificationsForIteration(".new.$it", ".touch.$it", ".delete.$it") }
|
||||||
.filter { it.isNotEmpty() }
|
.filter { it.isNotEmpty() }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -361,7 +370,7 @@ public abstract class AbstractIncrementalJpsTest(
|
|||||||
|
|
||||||
val modifications = getModificationsToPerform(moduleNames)
|
val modifications = getModificationsToPerform(moduleNames)
|
||||||
for (step in modifications) {
|
for (step in modifications) {
|
||||||
step.forEach { it.perform(workDir) }
|
step.forEach { it.perform(workDir, mapWorkingToOriginalFile) }
|
||||||
performAdditionalModifications(step)
|
performAdditionalModifications(step)
|
||||||
if (moduleNames == null) {
|
if (moduleNames == null) {
|
||||||
preProcessSources(File(workDir, "src"))
|
preProcessSources(File(workDir, "src"))
|
||||||
@@ -370,7 +379,7 @@ public abstract class AbstractIncrementalJpsTest(
|
|||||||
moduleNames.forEach { preProcessSources(File(workDir, "$it/src")) }
|
moduleNames.forEach { preProcessSources(File(workDir, "$it/src")) }
|
||||||
}
|
}
|
||||||
|
|
||||||
results.add(make(step))
|
results.add(make())
|
||||||
}
|
}
|
||||||
return results
|
return results
|
||||||
}
|
}
|
||||||
@@ -380,6 +389,16 @@ public abstract class AbstractIncrementalJpsTest(
|
|||||||
|
|
||||||
// null means one module
|
// null means one module
|
||||||
private fun configureModules(): Set<String>? {
|
private fun configureModules(): Set<String>? {
|
||||||
|
|
||||||
|
fun prepareSources(relativePathToSrc: String, filePrefix: String) {
|
||||||
|
val srcDir = File(workDir, relativePathToSrc)
|
||||||
|
FileUtil.copyDir(testDataDir, srcDir) { it.name.startsWith(filePrefix) && (it.name.endsWith(".kt") || it.name.endsWith(".java")) }
|
||||||
|
|
||||||
|
srcDir.walk().forEach { mapWorkingToOriginalFile[it] = File(testDataDir, filePrefix + it.name) }
|
||||||
|
|
||||||
|
preProcessSources(srcDir)
|
||||||
|
}
|
||||||
|
|
||||||
var moduleNames: Set<String>?
|
var moduleNames: Set<String>?
|
||||||
JpsJavaExtensionService.getInstance().getOrCreateProjectExtension(myProject).outputUrl = JpsPathUtil.pathToUrl(getAbsolutePath("out"))
|
JpsJavaExtensionService.getInstance().getOrCreateProjectExtension(myProject).outputUrl = JpsPathUtil.pathToUrl(getAbsolutePath("out"))
|
||||||
|
|
||||||
@@ -388,10 +407,7 @@ public abstract class AbstractIncrementalJpsTest(
|
|||||||
if (moduleDependencies == null) {
|
if (moduleDependencies == null) {
|
||||||
addModule("module", arrayOf(getAbsolutePath("src")), null, null, jdk)
|
addModule("module", arrayOf(getAbsolutePath("src")), null, null, jdk)
|
||||||
|
|
||||||
val srcDir = File(workDir, "src")
|
prepareSources(relativePathToSrc = "src", filePrefix = "")
|
||||||
FileUtil.copyDir(testDataDir, srcDir, { it.getName().endsWith(".kt") || it.getName().endsWith(".java") })
|
|
||||||
|
|
||||||
preProcessSources(srcDir)
|
|
||||||
|
|
||||||
moduleNames = null
|
moduleNames = null
|
||||||
}
|
}
|
||||||
@@ -410,12 +426,7 @@ public abstract class AbstractIncrementalJpsTest(
|
|||||||
|
|
||||||
for (module in nameToModule.values()) {
|
for (module in nameToModule.values()) {
|
||||||
val moduleName = module.name
|
val moduleName = module.name
|
||||||
|
prepareSources(relativePathToSrc = "$moduleName/src", filePrefix = moduleName + "_")
|
||||||
val srcDir = File(workDir, "$moduleName/src")
|
|
||||||
FileUtil.copyDir(testDataDir, srcDir,
|
|
||||||
{ it.getName().startsWith(moduleName + "_") && (it.getName().endsWith(".kt") || it.getName().endsWith(".java")) })
|
|
||||||
|
|
||||||
preProcessSources(srcDir)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
moduleNames = nameToModule.keySet()
|
moduleNames = nameToModule.keySet()
|
||||||
@@ -429,26 +440,37 @@ public abstract class AbstractIncrementalJpsTest(
|
|||||||
|
|
||||||
override fun doGetProjectDir(): File? = workDir
|
override fun doGetProjectDir(): File? = workDir
|
||||||
|
|
||||||
|
// TODO replace with org.jetbrains.jps.builders.TestProjectBuilderLogger
|
||||||
private class MyLogger(val rootPath: String) : ProjectBuilderLoggerBase() {
|
private class MyLogger(val rootPath: String) : ProjectBuilderLoggerBase() {
|
||||||
private val logBuf = StringBuilder()
|
private val logBuf = StringBuilder()
|
||||||
public val log: String
|
public val log: String
|
||||||
get() = logBuf.toString()
|
get() = logBuf.toString()
|
||||||
|
|
||||||
|
val compiledFiles = hashSetOf<File>()
|
||||||
|
|
||||||
override fun isEnabled(): Boolean = true
|
override fun isEnabled(): Boolean = true
|
||||||
|
|
||||||
|
override fun logCompiledFiles(files: MutableCollection<File>?, builderName: String?, description: String?) {
|
||||||
|
super.logCompiledFiles(files, builderName, description)
|
||||||
|
|
||||||
|
if (builderName == KotlinBuilder.KOTLIN_BUILDER_NAME) {
|
||||||
|
compiledFiles.addAll(files!!)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun logLine(message: String?) {
|
override fun logLine(message: String?) {
|
||||||
logBuf.append(JetTestUtils.replaceHashWithStar(message!!.removePrefix("$rootPath/"))).append('\n')
|
logBuf.append(JetTestUtils.replaceHashWithStar(message!!.removePrefix("$rootPath/"))).append('\n')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract class Modification(val path: String) {
|
protected abstract class Modification(val path: String) {
|
||||||
abstract fun perform(workDir: File)
|
abstract fun perform(workDir: File, mapping: MutableMap<File, File>)
|
||||||
|
|
||||||
override fun toString(): String = "${javaClass.simpleName} $path"
|
override fun toString(): String = "${javaClass.simpleName} $path"
|
||||||
}
|
}
|
||||||
|
|
||||||
protected class ModifyContent(path: String, val dataFile: File) : Modification(path) {
|
protected class ModifyContent(path: String, val dataFile: File) : Modification(path) {
|
||||||
override fun perform(workDir: File) {
|
override fun perform(workDir: File, mapping: MutableMap<File, File>) {
|
||||||
val file = File(workDir, path)
|
val file = File(workDir, path)
|
||||||
|
|
||||||
val oldLastModified = file.lastModified()
|
val oldLastModified = file.lastModified()
|
||||||
@@ -460,15 +482,29 @@ public abstract class AbstractIncrementalJpsTest(
|
|||||||
//Mac OS and some versions of Linux truncate timestamp to nearest second
|
//Mac OS and some versions of Linux truncate timestamp to nearest second
|
||||||
file.setLastModified(oldLastModified + 1000)
|
file.setLastModified(oldLastModified + 1000)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mapping[file] = dataFile
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected class TouchFile(path: String) : Modification(path) {
|
||||||
|
override fun perform(workDir: File, mapping: MutableMap<File, File>) {
|
||||||
|
val file = File(workDir, path)
|
||||||
|
|
||||||
|
val oldLastModified = file.lastModified()
|
||||||
|
//Mac OS and some versions of Linux truncate timestamp to nearest second
|
||||||
|
file.setLastModified(Math.max(System.currentTimeMillis(), oldLastModified + 1000))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected class DeleteFile(path: String) : Modification(path) {
|
protected class DeleteFile(path: String) : Modification(path) {
|
||||||
override fun perform(workDir: File) {
|
override fun perform(workDir: File, mapping: MutableMap<File, File>) {
|
||||||
val fileToDelete = File(workDir, path)
|
val fileToDelete = File(workDir, path)
|
||||||
if (!fileToDelete.delete()) {
|
if (!fileToDelete.delete()) {
|
||||||
throw AssertionError("Couldn't delete $fileToDelete")
|
throw AssertionError("Couldn't delete $fileToDelete")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mapping.remove(fileToDelete)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,11 +36,10 @@ abstract class AbstractLookupTrackerTest : AbstractIncrementalJpsTest(
|
|||||||
|
|
||||||
override fun createLookupTracker(): LookupTracker = TestLookupTracker()
|
override fun createLookupTracker(): LookupTracker = TestLookupTracker()
|
||||||
|
|
||||||
override fun checkLookups(modifications: List<Modification>, lookupTracker: LookupTracker) {
|
override fun checkLookups(lookupTracker: LookupTracker, compiledFiles: Set<File>) {
|
||||||
if (lookupTracker !is TestLookupTracker) throw AssertionError("Expected TestLookupTracker, but: ${lookupTracker.javaClass}")
|
if (lookupTracker !is TestLookupTracker) throw AssertionError("Expected TestLookupTracker, but: ${lookupTracker.javaClass}")
|
||||||
|
|
||||||
val fileToLookups = lookupTracker.lookups.groupBy { it.lookupContainingFile }
|
val fileToLookups = lookupTracker.lookups.groupBy { it.lookupContainingFile }
|
||||||
val workSrcDir = File(workDir, "src")
|
|
||||||
|
|
||||||
fun checkLookupsInFile(expectedFile: File, actualFile: File) {
|
fun checkLookupsInFile(expectedFile: File, actualFile: File) {
|
||||||
|
|
||||||
@@ -96,25 +95,10 @@ abstract class AbstractLookupTrackerTest : AbstractIncrementalJpsTest(
|
|||||||
JetTestUtils.assertEqualsToFile(expectedFile, actual)
|
JetTestUtils.assertEqualsToFile(expectedFile, actual)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (modifications.isNotEmpty()) {
|
for (actualFile in compiledFiles) {
|
||||||
for (modification in modifications) {
|
val expectedFile = mapWorkingToOriginalFile[actualFile]!!
|
||||||
if (modification !is ModifyContent) continue
|
|
||||||
|
|
||||||
val expectedFile = modification.dataFile
|
checkLookupsInFile(expectedFile, actualFile)
|
||||||
val actualFile = File(workDir, modification.path)
|
|
||||||
|
|
||||||
checkLookupsInFile(expectedFile, actualFile)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
for (actualFile in workSrcDir.walkTopDown()) {
|
|
||||||
if (!actualFile.isFile) continue
|
|
||||||
|
|
||||||
val independentFilePath = FileUtil.toSystemIndependentName(actualFile.path)
|
|
||||||
val expectedFile = File(testDataDir, independentFilePath.replace(".*/src/".toRegex(), ""))
|
|
||||||
|
|
||||||
checkLookupsInFile(expectedFile, actualFile)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user