Wizard: add common tests for iOS/Android template
This commit is contained in:
committed by
Kirill Shmakov
parent
5ffcaf6508
commit
b3d48cda8c
+3
-1
@@ -42,7 +42,9 @@ kotlin {
|
||||
}
|
||||
}
|
||||
androidTest {
|
||||
|
||||
dependencies {
|
||||
implementation 'junit:junit:4.12'
|
||||
}
|
||||
}
|
||||
iosMain {
|
||||
|
||||
|
||||
+5
-1
@@ -39,7 +39,11 @@ kotlin {
|
||||
implementation("androidx.core:core-ktx:1.2.0")
|
||||
}
|
||||
}
|
||||
val androidTest by getting
|
||||
val androidTest by getting {
|
||||
dependencies {
|
||||
implementation("junit:junit:4.12")
|
||||
}
|
||||
}
|
||||
val iosMain by getting
|
||||
val iosTest by getting
|
||||
}
|
||||
|
||||
+3
-1
@@ -40,7 +40,9 @@ kotlin {
|
||||
}
|
||||
}
|
||||
androidTest {
|
||||
|
||||
dependencies {
|
||||
implementation 'junit:junit:4.12'
|
||||
}
|
||||
}
|
||||
iosMain {
|
||||
|
||||
|
||||
+5
-1
@@ -37,7 +37,11 @@ kotlin {
|
||||
implementation("androidx.core:core-ktx:1.2.0")
|
||||
}
|
||||
}
|
||||
val androidTest by getting
|
||||
val androidTest by getting {
|
||||
dependencies {
|
||||
implementation("junit:junit:4.12")
|
||||
}
|
||||
}
|
||||
val iosMain by getting
|
||||
val iosTest by getting
|
||||
}
|
||||
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
import org.junit.Assert.assertTrue
|
||||
import org.junit.Test
|
||||
|
||||
class GreetingTest {
|
||||
|
||||
@Test
|
||||
fun testExample() {
|
||||
assertTrue("Check Android is mentioned", Greeting().greeting().contains("Android"))
|
||||
}
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertTrue
|
||||
|
||||
class GreetingTest {
|
||||
|
||||
@Test
|
||||
fun testExample() {
|
||||
assertTrue(Greeting().greeting().contains("iOS"), "Check iOS is mentioned")
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -1,7 +1,7 @@
|
||||
import XCTest
|
||||
@testable import appName
|
||||
@testable import $moduleName
|
||||
|
||||
class appNameTests: XCTestCase {
|
||||
class ${moduleName}Tests: XCTestCase {
|
||||
|
||||
override func setUp() {
|
||||
// Put setup code here. This method is called before the invocation of each test method in the class.
|
||||
+1
@@ -12,6 +12,7 @@ object Versions {
|
||||
val KOTLIN = version("1.4-M1") // used as fallback version
|
||||
val GRADLE = version("6.3")
|
||||
val KTOR: (kotlinVersion: Version) -> Version = { kotlinVersion -> version("1.3.2-$kotlinVersion") }
|
||||
val JUNIT = version("4.12")
|
||||
|
||||
object ANDROID {
|
||||
val ANDROIDX_CORE_KTX = version("1.2.0")
|
||||
|
||||
+4
-2
@@ -69,7 +69,9 @@ data class ProjectImportingError(val kotlinVersion: String, @Nls val reason: Str
|
||||
""".trimMargin()
|
||||
}
|
||||
|
||||
data class InvalidModuleDependencyError(val from: Module, val to: Module, @Nls val reason: String? = null) : Error() {
|
||||
data class InvalidModuleDependencyError(val from: String, val to: String, @Nls val reason: String? = null) : Error() {
|
||||
constructor(from: Module, to: Module, reason: String? = null) : this(from.name, to.name, reason)
|
||||
|
||||
override val message: String
|
||||
get() = KotlinNewProjectWizardBundle.message("error.invalid.module.dependency", from.name, to.name) + reason?.let { ": $it" }
|
||||
get() = KotlinNewProjectWizardBundle.message("error.invalid.module.dependency", from, to) + reason?.let { ": $it" }
|
||||
}
|
||||
+2
-1
@@ -35,7 +35,8 @@ abstract class TemplateEngineService : WizardService {
|
||||
is FileTemplateDescriptor -> renderTemplate(descriptor, template.data)
|
||||
is FileTextDescriptor -> descriptor.text
|
||||
}
|
||||
val text = formatter.formatFile(unformattedText, template.descriptor.relativePath.fileName.toString())
|
||||
val fileName = template.descriptor.relativePath?.fileName?.toString()
|
||||
val text = fileName?.let { formatter.formatFile(unformattedText, it) } ?: unformattedText
|
||||
return service<FileSystemWizardService>().createFile(template.rootPath / template.descriptor.relativePath, text)
|
||||
}
|
||||
}
|
||||
|
||||
+23
-1
@@ -153,7 +153,18 @@ object AndroidTargetConfigurator : TargetConfigurator,
|
||||
modulePath: Path
|
||||
): TaskResult<Unit> = computeM {
|
||||
val javaPackage = module.javaPackage(configurationData.pomIr)
|
||||
val settings = mapOf("package" to javaPackage.asCodePackage())
|
||||
|
||||
val sharedModule = configurationData.getDependentModules(module).get().find { dependency ->
|
||||
dependency.configurator is MppModuleConfigurator
|
||||
}
|
||||
|
||||
val sharedPackage = sharedModule?.javaPackage(configurationData.pomIr)
|
||||
|
||||
val settings = mapOf(
|
||||
"package" to javaPackage.asCodePackage(),
|
||||
"sharedPackage" to sharedPackage?.asCodePackage()
|
||||
)
|
||||
|
||||
TemplatesPlugin.addFileTemplates.execute(
|
||||
listOf(
|
||||
FileTemplate(AndroidModuleConfigurator.FileTemplateDescriptors.androidManifestForLibraryXml, modulePath, settings)
|
||||
@@ -161,6 +172,17 @@ object AndroidTargetConfigurator : TargetConfigurator,
|
||||
)
|
||||
}
|
||||
|
||||
override fun createModuleIRs(reader: Reader, configurationData: ModulesToIrConversionData, module: Module): List<BuildSystemIR> =
|
||||
buildList {
|
||||
+super<AndroidModuleConfigurator>.createModuleIRs(reader, configurationData, module)
|
||||
+ArtifactBasedLibraryDependencyIR(
|
||||
MavenArtifact(DefaultRepository.MAVEN_CENTRAL, "junit", "junit"),
|
||||
version = Versions.JUNIT,
|
||||
dependencyType = DependencyType.TEST
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
val androidPlugin by enumSetting<AndroidGradlePlugin>(
|
||||
KotlinNewProjectWizardBundle.message("module.configurator.android.setting.android.plugin"),
|
||||
neededAtPhase = GenerationPhase.PROJECT_GENERATION
|
||||
|
||||
+1
-1
@@ -66,7 +66,7 @@ object IOSSinglePlatformModuleConfigurator : SinglePlatformModuleConfigurator,
|
||||
+fileTemplate(DEFAULT_APP_NAME / "Preview_Content" / "Preview_Assets.xcassets" / "Contents.json")
|
||||
|
||||
+fileTemplate("${DEFAULT_APP_NAME}Tests" / "Info.plist")
|
||||
+fileTemplate("${DEFAULT_APP_NAME}Tests" / "${DEFAULT_APP_NAME}Tests.swift")
|
||||
+fileTemplate("${DEFAULT_APP_NAME}Tests" / "${DEFAULT_APP_NAME}Tests.swift.vm")
|
||||
|
||||
+fileTemplate("${DEFAULT_APP_NAME}UITests" / "Info.plist")
|
||||
+fileTemplate("${DEFAULT_APP_NAME}UITests" / "${DEFAULT_APP_NAME}UITests.swift")
|
||||
|
||||
+93
-19
@@ -17,7 +17,10 @@ import org.jetbrains.kotlin.tools.projectWizard.plugins.templates.TemplatesPlugi
|
||||
import org.jetbrains.kotlin.tools.projectWizard.settings.JavaPackage
|
||||
import org.jetbrains.kotlin.tools.projectWizard.settings.buildsystem.Module
|
||||
import org.jetbrains.kotlin.tools.projectWizard.settings.buildsystem.ModuleKind
|
||||
import org.jetbrains.kotlin.tools.projectWizard.settings.buildsystem.SourcesetType
|
||||
import org.jetbrains.kotlin.tools.projectWizard.templates.FileDescriptor
|
||||
import org.jetbrains.kotlin.tools.projectWizard.templates.FileTemplate
|
||||
import org.jetbrains.kotlin.tools.projectWizard.templates.FileTemplateDescriptorWithPath
|
||||
import org.jetbrains.kotlin.tools.projectWizard.templates.FileTextDescriptor
|
||||
import java.nio.file.Path
|
||||
|
||||
@@ -43,23 +46,33 @@ object MppModuleConfigurator : ModuleConfigurator,
|
||||
version = configurationData.kotlinVersion
|
||||
)
|
||||
|
||||
val mppFiles by listProperty<MppFile>()
|
||||
val mppSources by listProperty<MppSources>()
|
||||
|
||||
override fun getConfiguratorProperties(): List<ModuleConfiguratorProperty<*>> =
|
||||
listOf(mppFiles)
|
||||
listOf(mppSources)
|
||||
|
||||
override fun Writer.runArbitraryTask(
|
||||
configurationData: ModulesToIrConversionData,
|
||||
module: Module,
|
||||
modulePath: Path,
|
||||
): TaskResult<Unit> = compute {
|
||||
createMppFiles(module, modulePath).ensure()
|
||||
createSimpleFiles(module, modulePath).ensure()
|
||||
}
|
||||
|
||||
private fun Writer.createMppFiles(
|
||||
module: Module,
|
||||
modulePath: Path
|
||||
): TaskResult<Unit> = inContextOfModuleConfigurator(module) {
|
||||
val mppFiles = mppFiles.reference.propertyValue.distinctBy { it.fileNameWithPackage } // todo merge files with the same name here
|
||||
val mppFiles = mppSources.reference.propertyValue.flatMap { it.mppFiles }
|
||||
.distinctBy { it.fileNameWithPackage } // todo merge files with the same name here
|
||||
mppFiles.mapSequenceIgnore { file ->
|
||||
module.subModules.mapSequenceIgnore mapTargets@{ target ->
|
||||
val moduleSubType = //TODO handle for non-simple target configurator
|
||||
target.configurator.safeAs<SimpleTargetConfigurator>()?.moduleSubType ?: return@mapTargets UNIT_SUCCESS
|
||||
val path = pathForFileInTarget(modulePath, module, file.javaPackage, file.filename, target, SourcesetType.main)
|
||||
val fileTemplate = FileTemplate(
|
||||
FileTextDescriptor(file.printForModuleSubType(moduleSubType), pathForFileInTarget(modulePath, module, file, target)),
|
||||
FileTextDescriptor(file.printForModuleSubType(moduleSubType), path),
|
||||
projectPath,
|
||||
)
|
||||
TemplatesPlugin.fileTemplatesToRender.addValues(fileTemplate)
|
||||
@@ -67,13 +80,38 @@ object MppModuleConfigurator : ModuleConfigurator,
|
||||
}
|
||||
}
|
||||
|
||||
private fun pathForFileInTarget(mppModulePath: Path, mppModule: Module, file: MppFile, target: Module) =
|
||||
mppModulePath /
|
||||
Defaults.SRC_DIR /
|
||||
"${target.name}Main" /
|
||||
mppModule.configurator.kotlinDirectoryName /
|
||||
file.javaPackage?.asPath() /
|
||||
file.filename
|
||||
private fun Writer.createSimpleFiles(
|
||||
module: Module,
|
||||
modulePath: Path
|
||||
): TaskResult<Unit> = inContextOfModuleConfigurator(module) {
|
||||
val mppFiles = mppSources.reference.propertyValue
|
||||
module.subModules.mapSequenceIgnore mapTargets@{ target ->
|
||||
val moduleSubType = //TODO handle for non-simple target configurator
|
||||
target.configurator.safeAs<SimpleTargetConfigurator>()?.moduleSubType ?: return@mapTargets UNIT_SUCCESS
|
||||
val files = mppFiles.flatMap { it.getFilesFor(moduleSubType) }.distinctBy { it.uniqueIdentifier }
|
||||
val fileTemplates = files.map { file ->
|
||||
FileTemplate(
|
||||
file.fileDescriptor,
|
||||
projectPath / pathForFileInTarget(modulePath, module, file.javaPackage, file.filename, target, file.type),
|
||||
)
|
||||
}
|
||||
TemplatesPlugin.fileTemplatesToRender.addValues(fileTemplates)
|
||||
}
|
||||
}
|
||||
|
||||
private fun pathForFileInTarget(
|
||||
mppModulePath: Path,
|
||||
mppModule: Module,
|
||||
javaPackage: JavaPackage?,
|
||||
filename: String,
|
||||
target: Module,
|
||||
sourcesetType: SourcesetType,
|
||||
) = mppModulePath /
|
||||
Defaults.SRC_DIR /
|
||||
"${target.name}${sourcesetType.name.capitalize()}" /
|
||||
mppModule.configurator.kotlinDirectoryName /
|
||||
javaPackage?.asPath() /
|
||||
filename
|
||||
}
|
||||
|
||||
|
||||
@@ -123,19 +161,55 @@ data class MppFile(
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ExpectFileDSL
|
||||
class MppFilesListBuilder {
|
||||
private val expectFiles = mutableListOf<MppFile>()
|
||||
class MppSources(val mppFiles: List<MppFile>, val simpleFiles: List<SimpleFiles>) {
|
||||
|
||||
fun mppfile(filename: String, init: MppFile.Builder.() -> Unit) {
|
||||
expectFiles += MppFile.Builder(filename).apply(init).build()
|
||||
fun getFilesFor(moduleSubType: ModuleSubType): List<SimpleFile> =
|
||||
simpleFiles.filter { moduleSubType in it.moduleSubTypes }.flatMap { it.files }
|
||||
|
||||
class Builder {
|
||||
private val mppFiles = mutableListOf<MppFile>()
|
||||
private val simpleFiles = mutableListOf<SimpleFiles>()
|
||||
|
||||
fun mppFile(filename: String, init: MppFile.Builder.() -> Unit) {
|
||||
mppFiles += MppFile.Builder(filename).apply(init).build()
|
||||
}
|
||||
|
||||
fun filesFor(vararg moduleSubTypes: ModuleSubType, init: SimpleFiles.Builder.() -> Unit) {
|
||||
simpleFiles += SimpleFiles.Builder(moduleSubTypes.toList()).apply(init).build()
|
||||
}
|
||||
|
||||
fun build() = MppSources(mppFiles, simpleFiles)
|
||||
}
|
||||
|
||||
fun build(): List<MppFile> = expectFiles
|
||||
}
|
||||
|
||||
fun mppFiles(init: MppFilesListBuilder.() -> Unit): List<MppFile> =
|
||||
MppFilesListBuilder().apply(init).build()
|
||||
|
||||
data class SimpleFiles(val moduleSubTypes: List<ModuleSubType>, val files: List<SimpleFile>) {
|
||||
class Builder(private val moduleSubTypes: List<ModuleSubType>) {
|
||||
private val files = mutableListOf<SimpleFile>()
|
||||
|
||||
fun file(fileDescriptor: FileDescriptor, filename: String, type: SourcesetType, init: SimpleFile.Builder.() -> Unit = {}) {
|
||||
files += SimpleFile.Builder(fileDescriptor, filename, type).apply(init).build()
|
||||
}
|
||||
|
||||
fun build() = SimpleFiles(moduleSubTypes, files)
|
||||
}
|
||||
}
|
||||
|
||||
data class SimpleFile(val fileDescriptor: FileDescriptor, val javaPackage: JavaPackage?, val filename: String, val type: SourcesetType) {
|
||||
val uniqueIdentifier get() = "${type}/${javaPackage}/${filename}"
|
||||
|
||||
class Builder(private val fileDescriptor: FileDescriptor, private val filename: String, private val type: SourcesetType) {
|
||||
var javaPackage: JavaPackage? = null
|
||||
|
||||
fun build() = SimpleFile(fileDescriptor, javaPackage, filename, type)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fun mppSources(init: MppSources.Builder.() -> Unit): MppSources =
|
||||
MppSources.Builder().apply(init).build()
|
||||
|
||||
sealed class MppDeclaration {
|
||||
@Suppress("SpellCheckingInspection")
|
||||
|
||||
-2
@@ -16,8 +16,6 @@ import org.jetbrains.kotlin.tools.projectWizard.plugins.buildSystem.BuildSystemT
|
||||
import org.jetbrains.kotlin.tools.projectWizard.plugins.buildSystem.isGradle
|
||||
import org.jetbrains.kotlin.tools.projectWizard.plugins.kotlin.ModuleType
|
||||
import org.jetbrains.kotlin.tools.projectWizard.plugins.kotlin.ModulesToIrConversionData
|
||||
import org.jetbrains.kotlin.tools.projectWizard.plugins.kotlin.ModuleType
|
||||
import org.jetbrains.kotlin.tools.projectWizard.plugins.kotlin.ModulesToIrConversionData
|
||||
import org.jetbrains.kotlin.tools.projectWizard.settings.DisplayableSettingItem
|
||||
import org.jetbrains.kotlin.tools.projectWizard.settings.buildsystem.Module
|
||||
import org.jetbrains.kotlin.tools.projectWizard.settings.buildsystem.ModuleKind
|
||||
|
||||
+5
@@ -28,6 +28,11 @@ data class ModulesToIrConversionData(
|
||||
val isSingleRootModuleMode = rootModules.size == 1
|
||||
|
||||
val moduleByPath = rootModules.withAllSubModules(includeSourcesets = true).associateBy(Module::path)
|
||||
|
||||
fun getDependentModules(from: Module): TaskResult<List<Module>> =
|
||||
from.dependencies.mapSequence { to ->
|
||||
moduleByPath[to.path].toResult { InvalidModuleDependencyError(from.name, to.path.toString()) }
|
||||
}
|
||||
}
|
||||
|
||||
private data class ModulesToIrsState(
|
||||
|
||||
+13
-4
@@ -21,6 +21,7 @@ import org.jetbrains.kotlin.tools.projectWizard.plugins.projectPath
|
||||
import org.jetbrains.kotlin.tools.projectWizard.plugins.templates.TemplatesPlugin
|
||||
import org.jetbrains.kotlin.tools.projectWizard.templates.FileTemplate
|
||||
import org.jetbrains.kotlin.tools.projectWizard.templates.FileTemplateDescriptor
|
||||
import org.jetbrains.kotlin.tools.projectWizard.templates.asSrcOf
|
||||
import java.nio.file.Path
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
@@ -112,7 +113,7 @@ sealed class ModuleDependencyType(
|
||||
to: Module,
|
||||
toModulePath: Path,
|
||||
): TaskResult<Unit> {
|
||||
val needDummyFile = inContextOfModuleConfigurator(to) { MppModuleConfigurator.mppFiles.reference.propertyValue.isEmpty() }
|
||||
val needDummyFile = inContextOfModuleConfigurator(to) { MppModuleConfigurator.mppSources.reference.propertyValue.isEmpty() }
|
||||
return if (needDummyFile) {
|
||||
val dummyFilePath =
|
||||
Defaults.SRC_DIR / "${to.iosTargetSafe()!!.name}Main" / to.configurator.kotlinDirectoryName / "dummyFile.kt"
|
||||
@@ -184,8 +185,8 @@ sealed class ModuleDependencyType(
|
||||
}
|
||||
|
||||
private fun Writer.addExpectFilesForMppModuleForAndroidAndIos(mppModule: Module): TaskResult<Unit> {
|
||||
val expectFiles = mppFiles {
|
||||
mppfile("Platform.kt") {
|
||||
val expectFiles = mppSources {
|
||||
mppFile("Platform.kt") {
|
||||
`class`("Platform") {
|
||||
expectBody = "val platform: String"
|
||||
actualFor(
|
||||
@@ -202,6 +203,14 @@ private fun Writer.addExpectFilesForMppModuleForAndroidAndIos(mppModule: Module)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
filesFor(ModuleSubType.android) {
|
||||
file(FileTemplateDescriptor("android/androidTest.kt.vm", relativePath = null), "androidTest.kt", SourcesetType.test)
|
||||
}
|
||||
|
||||
filesFor(ModuleSubType.iosArm64, ModuleSubType.iosX64) {
|
||||
file(FileTemplateDescriptor("ios/iosTest.kt.vm", relativePath = null), "iosTest.kt", SourcesetType.test)
|
||||
}
|
||||
}
|
||||
return inContextOfModuleConfigurator(mppModule) { MppModuleConfigurator.mppFiles.reference.addValues(expectFiles) }
|
||||
return inContextOfModuleConfigurator(mppModule) { MppModuleConfigurator.mppSources.reference.addValues(listOf(expectFiles)) }
|
||||
}
|
||||
+2
-2
@@ -9,10 +9,10 @@ import java.nio.file.Paths
|
||||
// Should be used to create any kind of files in the generated project
|
||||
// Except build files as they will be generated using IR
|
||||
sealed class FileDescriptor {
|
||||
abstract val relativePath: Path
|
||||
abstract val relativePath: Path?
|
||||
}
|
||||
|
||||
data class FileTemplateDescriptor(@NonNls val templateId: String, override val relativePath: Path) : FileDescriptor() {
|
||||
data class FileTemplateDescriptor(@NonNls val templateId: String, override val relativePath: Path?) : FileDescriptor() {
|
||||
constructor(templateId: String) : this(
|
||||
templateId,
|
||||
Paths.get(templateId).fileName.toString().removeSuffix(".vm").asPath()
|
||||
|
||||
+9
-9
@@ -5,7 +5,7 @@
|
||||
|
||||
package org.jetbrains.kotlin.tools.projectWizard.core
|
||||
|
||||
import org.jetbrains.kotlin.tools.projectWizard.moduleConfigurators.mppFiles
|
||||
import org.jetbrains.kotlin.tools.projectWizard.moduleConfigurators.mppSources
|
||||
import org.jetbrains.kotlin.tools.projectWizard.plugins.kotlin.ModuleSubType
|
||||
import org.junit.Test
|
||||
import kotlin.test.assertEquals
|
||||
@@ -13,8 +13,8 @@ import kotlin.test.assertEquals
|
||||
class ExpectedFileTest {
|
||||
@Test
|
||||
fun `it should generate valid expect functions`() {
|
||||
val file = mppFiles {
|
||||
mppfile("file") {
|
||||
val file = mppSources {
|
||||
mppFile("file") {
|
||||
function("f(x: Int): String")
|
||||
function("y(x: Int): String")
|
||||
}
|
||||
@@ -30,8 +30,8 @@ class ExpectedFileTest {
|
||||
|
||||
@Test
|
||||
fun `it should generate valid expect classes`() {
|
||||
val file = mppFiles {
|
||||
mppfile("file") {
|
||||
val file = mppSources {
|
||||
mppFile("file") {
|
||||
`class`("A")
|
||||
`class`("B")
|
||||
}
|
||||
@@ -47,8 +47,8 @@ class ExpectedFileTest {
|
||||
|
||||
@Test
|
||||
fun `it should generate valid actual functions`() {
|
||||
val file = mppFiles {
|
||||
mppfile("file") {
|
||||
val file = mppSources {
|
||||
mppFile("file") {
|
||||
function("foo()") {
|
||||
actualFor(
|
||||
ModuleSubType.jvm,
|
||||
@@ -92,8 +92,8 @@ class ExpectedFileTest {
|
||||
|
||||
@Test
|
||||
fun `it should generate valid actual classes`() {
|
||||
val file = mppFiles {
|
||||
mppfile("file") {
|
||||
val file = mppSources {
|
||||
mppFile("file") {
|
||||
`class`("A") {
|
||||
actualFor(
|
||||
ModuleSubType.jvm,
|
||||
|
||||
Reference in New Issue
Block a user