Provide sync issues with initialization result; Build tooling api modules before building app module

This commit is contained in:
Akash Yadav
2022-04-29 17:43:35 +05:30
parent 2c407de8aa
commit 1331ff89c7
15 changed files with 245 additions and 136 deletions
+38 -34
View File
@@ -4,60 +4,60 @@ apply plugin: 'kotlin-android'
android {
compileSdkVersion rootProject.ext.compileSdk
buildToolsVersion rootProject.ext.buildTools
defaultConfig {
applicationId rootProject.ext.packageName
minSdkVersion rootProject.ext.minSdk
targetSdkVersion rootProject.ext.targetSdk
versionCode rootProject.ext.versionCode
versionName rootProject.ext.versionName
multiDexEnabled true
vectorDrawables.useSupportLibrary = true
}
compileOptions {
coreLibraryDesugaringEnabled true
sourceCompatibility rootProject.ext.javaSourceVersion
targetCompatibility rootProject.ext.javaTargetVersion
}
kotlinOptions {
jvmTarget = "11"
}
buildFeatures {
viewBinding true
}
signingConfigs {
debug {
storeFile file("dev.keystore")
storeFile file ("dev.keystore")
keyAlias "androidide"
storePassword "ed68424fb109e5aa8146e4b86caa72e3"
keyPassword "ed68424fb109e5aa8146e4b86caa72e3"
}
release {
storeFile file("dev.keystore")
storeFile file ("dev.keystore")
keyAlias "androidide"
storePassword "ed68424fb109e5aa8146e4b86caa72e3"
keyPassword "ed68424fb109e5aa8146e4b86caa72e3"
}
}
buildTypes {
debug {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
proguardFiles getDefaultProguardFile ('proguard-android-optimize.txt'), 'proguard-rules.pro'
signingConfig signingConfigs.debug
}
release {
minifyEnabled true
shrinkResources true
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
proguardFiles getDefaultProguardFile ('proguard-android-optimize.txt'), 'proguard-rules.pro'
signingConfig signingConfigs.release
}
}
@@ -66,7 +66,7 @@ android {
excludes += ['META-INF/eclipse.inf', 'about_files/LICENSE-2.0.txt', 'plugin.xml', 'plugin.properties', 'about.mappings', 'about.properties', 'about.ini', 'modeling32.png']
}
}
lint {
abortOnError false
disable 'VectorPath', 'NestedWeights', 'ContentDescription', 'SmallSp'
@@ -74,10 +74,10 @@ android {
}
dependencies {
// Annotation processors
annotationProcessor 'com.github.bumptech.glide:compiler:4.13.1'
implementation common.editor
implementation common.utilcode
implementation common.file_picker
@@ -87,9 +87,9 @@ dependencies {
implementation common.xml2json
implementation google.gson
implementation google.guava
implementation common.jsoup
// AndroidX
implementation androidx.annotation
implementation androidx.appcompat
@@ -103,24 +103,28 @@ dependencies {
implementation androidx.vectors
implementation androidx.animated_vectors
implementation google.material
// Kotlin
implementation "androidx.core:core-ktx:1.7.0"
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
// Local projects here
implementation project(':treeview')
implementation project(':emulatorview')
implementation project(':xml-inflater')
implementation project(':lexers')
implementation project(':common')
implementation project(':actions')
implementation project(':lsp:api')
implementation project(':lsp:java')
implementation project(':lsp:xml')
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation project (':treeview')
implementation project (':emulatorview')
implementation project (':xml-inflater')
implementation project (':lexers')
implementation project (':common')
implementation project (':actions')
implementation project (':lsp:api')
implementation project (':lsp:java')
implementation project (':lsp:xml')
implementation fileTree (dir: 'libs', include: ['*.jar'])
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.1.5'
// This is to build the tooling-api-impl project before the app is built
// So we always copy the latest JAR file to assets
compileOnly project (path: ':build-tools:tooling-api-impl')
}
Binary file not shown.
+4
View File
@@ -24,6 +24,10 @@ java {
targetCompatibility rootProject.ext.javaTargetVersion
}
dependencies {
api project (path: ':build-tools:tooling-api')
}
repositories {
mavenCentral ()
}
@@ -17,7 +17,10 @@
package com.itsaky.androidide.builder
import com.itsaky.androidide.tooling.api.messages.result.InitializeResult
import com.itsaky.androidide.tooling.api.messages.result.TaskExecutionResult
import java.io.File
import java.util.concurrent.*
/**
* A build service provides API to initialize project, execute builds, query a build, cancel running
@@ -31,17 +34,21 @@ interface BuildService {
* Initialize the project.
*
* @param rootDir The root directory of the project to initialize.
* @return A [CompletableFuture] which returns an [InitializeResult] when the project
* initialization process finishes.
*/
fun initializeProject(rootDir: File)
fun initializeProject(rootDir: File): CompletableFuture<InitializeResult>
/**
* Execute the given tasks.
*
* @param tasks The tasks to execute. If the fully qualified path of the task is not specified,
* then it will be executed in the root project directory.
* @return A [CompletableFuture] which returns a list of [TaskExecutionResult]. The result
* contains a list of tasks that were executed and the result of the whole execution.
* @see BuildService.executeProjectTasks
*/
fun executeTasks(vararg tasks: String)
fun executeTasks(vararg tasks: String): CompletableFuture<TaskExecutionResult>
/**
* Execute the given tasks of the given project.
@@ -51,6 +58,11 @@ interface BuildService {
* project. If the task name is not fully qualified, then it will be executed in the given
* project path. For example, if the project path is ':app' and the task is 'assembleDebug',
* then, ':app:assembleDebug' task will be executed.
* @return A [CompletableFuture] which returns a list of [TaskExecutionResult]. The result
* contains a list of tasks that were executed and the result of the whole execution.
*/
fun executeProjectTasks(projectPath: String, vararg tasks: String)
fun executeProjectTasks(
projectPath: String,
vararg tasks: String
): CompletableFuture<TaskExecutionResult>
}
@@ -20,7 +20,9 @@ package com.itsaky.androidide.tooling.impl
import com.itsaky.androidide.tooling.api.IToolingApiClient
import com.itsaky.androidide.tooling.api.IToolingApiServer
import com.itsaky.androidide.tooling.api.messages.InitializeProjectMessage
import com.itsaky.androidide.tooling.api.messages.result.InitializeResult
import com.itsaky.androidide.tooling.api.model.IdeGradleProject
import com.itsaky.androidide.tooling.api.model.internal.DefaultProjectSyncIssues
import com.itsaky.androidide.tooling.impl.util.InitScriptHandler
import com.itsaky.androidide.tooling.impl.util.ProjectReader
import com.itsaky.androidide.tooling.impl.util.StopWatch
@@ -43,7 +45,7 @@ internal class ToolingApiServerImpl : IToolingApiServer {
private var project: IdeGradleProject? = null
private val log = ILogger.newInstance(javaClass.simpleName)
override fun initialize(params: InitializeProjectMessage): CompletableFuture<IdeGradleProject?> {
override fun initialize(params: InitializeProjectMessage): CompletableFuture<InitializeResult> {
return CompletableFutures.computeAsync {
val stopWatch = StopWatch("Connection to project")
this.connector = GradleConnector.newConnector().forProjectDirectory(params.directory)
@@ -58,7 +60,8 @@ internal class ToolingApiServerImpl : IToolingApiServer {
val connection = this.connector!!.connect()
stopWatch.lapFromLast("Project connection established")
this.project = ProjectReader.read(connection)
val issues: MutableMap<String, DefaultProjectSyncIssues> = mutableMapOf()
this.project = ProjectReader.read(connection, issues)
stopWatch.lapFromLast(
"Project read ${if(this.project == null) "failed" else "successful"}")
@@ -66,7 +69,7 @@ internal class ToolingApiServerImpl : IToolingApiServer {
stopWatch.log()
initialized = true
return@computeAsync this.project
return@computeAsync InitializeResult(project, issues)
}
}
@@ -21,10 +21,12 @@ import static com.itsaky.androidide.utils.ILogger.newInstance;
import com.android.builder.model.v2.models.AndroidProject;
import com.android.builder.model.v2.models.ModelBuilderParameter;
import com.android.builder.model.v2.models.ProjectSyncIssues;
import com.android.builder.model.v2.models.VariantDependencies;
import com.itsaky.androidide.tooling.api.model.IdeAndroidModule;
import com.itsaky.androidide.tooling.api.model.IdeGradleProject;
import com.itsaky.androidide.tooling.api.model.IdeGradleTask;
import com.itsaky.androidide.tooling.api.model.internal.DefaultProjectSyncIssues;
import com.itsaky.androidide.tooling.api.model.internal.DefaultVariant;
import com.itsaky.androidide.tooling.api.model.util.AndroidModulePropertyCopier;
import com.itsaky.androidide.tooling.api.model.util.ProjectBuilder;
@@ -38,6 +40,8 @@ import org.gradle.tooling.UnknownModelException;
import org.gradle.tooling.model.GradleProject;
import org.gradle.tooling.model.GradleTask;
import java.util.Map;
/**
* @author Akash Yadav
*/
@@ -45,17 +49,20 @@ public class ProjectReader {
private static final ILogger LOG = newInstance("test");
public static IdeGradleProject read(ProjectConnection connection) {
public static IdeGradleProject read(
ProjectConnection connection, Map<String, DefaultProjectSyncIssues> outIssues) {
final var gradleModel = connection.getModel(GradleProject.class);
if (gradleModel == null) {
return null;
}
return buildProjectModel(connection, gradleModel);
return buildProjectModel(connection, gradleModel, outIssues);
}
private static IdeGradleProject buildProjectModel(
ProjectConnection connection, GradleProject gradleModel) {
ProjectConnection connection,
GradleProject gradleModel,
Map<String, DefaultProjectSyncIssues> outIssues) {
try {
final var modelBuilder = connection.model(AndroidProject.class);
addProperty(modelBuilder, AndroidProject.PROPERTY_BUILD_MODEL_ONLY, true);
@@ -67,19 +74,17 @@ public class ProjectReader {
"Project " + gradleModel.getPath() + " is not an Android project.");
}
final var module = buildAndroidProjectModel(gradleModel, android);
final var module = buildAndroidProjectModel(gradleModel, android, outIssues);
readDependencies(connection, module);
try {
tryReadDependencies(connection, module);
} catch (Throwable err) {
LOG.error("Unable to fetch dependencies for project", module.getProjectPath(), err);
}
final var issues = readSyncIssues(connection);
outIssues.put(gradleModel.getPath(), issues);
return module;
} catch (Throwable error) {
try {
LOG.info("Building IdeGradleProject model for project:", gradleModel.getPath());
return buildGradleProjectModel(gradleModel);
return buildGradleProjectModel(gradleModel, outIssues);
} catch (Throwable e) {
LOG.error("Unable to create model for project", e);
return null;
@@ -87,8 +92,16 @@ public class ProjectReader {
}
}
private static void tryReadDependencies(
ProjectConnection connection, IdeAndroidModule android) {
private static DefaultProjectSyncIssues readSyncIssues(ProjectConnection connection) {
final var builder = connection.model(ProjectSyncIssues.class);
addProperty(builder, AndroidProject.PROPERTY_BUILD_MODEL_ONLY, true);
addProperty(builder, AndroidProject.PROPERTY_INVOKED_FROM_IDE, true);
final var issues = builder.get();
return AndroidModulePropertyCopier.INSTANCE.copy(issues);
}
private static void readDependencies(ProjectConnection connection, IdeAndroidModule android) {
for (final var variant : android.getVariants()) {
fillVariantDependencies(connection, android, variant);
@@ -128,7 +141,9 @@ public class ProjectReader {
}
private static IdeAndroidModule buildAndroidProjectModel(
GradleProject gradle, AndroidProject android) {
GradleProject gradle,
AndroidProject android,
Map<String, DefaultProjectSyncIssues> outIssues) {
LOG.debug("Building IdeAndroidModule for project:", gradle.getPath());
final var builder = new ProjectBuilder();
final var copier = AndroidModulePropertyCopier.INSTANCE;
@@ -153,13 +168,14 @@ public class ProjectReader {
builder.setLintRuleJars(android.getLintRuleJars());
final var module = builder.buildAndroidModule();
addSubprojects(gradle, module);
addSubprojects(gradle, module, outIssues);
addTasks(gradle, module);
return module;
}
private static IdeGradleProject buildGradleProjectModel(GradleProject gradle) {
private static IdeGradleProject buildGradleProjectModel(
GradleProject gradle, Map<String, DefaultProjectSyncIssues> outIssues) {
final var builder = new ProjectBuilder();
builder.setName(gradle.getName());
builder.setDescription(gradle.getDescription());
@@ -169,7 +185,7 @@ public class ProjectReader {
builder.setBuildScript(gradle.getBuildScript().getSourceFile());
final var project = builder.buildGradleProject();
addSubprojects(gradle, project);
addSubprojects(gradle, project, outIssues);
addTasks(gradle, project);
return project;
@@ -181,13 +197,16 @@ public class ProjectReader {
}
}
private static void addSubprojects(GradleProject gradle, IdeGradleProject project) {
private static void addSubprojects(
GradleProject gradle,
IdeGradleProject project,
Map<String, DefaultProjectSyncIssues> outIssues) {
for (final var subGradle : gradle.getChildren()) {
final var connection =
GradleConnector.newConnector()
.forProjectDirectory(subGradle.getProjectDirectory())
.connect();
final var sub = buildProjectModel(connection, subGradle);
final var sub = buildProjectModel(connection, subGradle, outIssues);
if (sub != null) {
project.getSubprojects().add(sub);
}
@@ -27,13 +27,13 @@ import com.itsaky.androidide.tooling.api.model.IdeAndroidModule
import com.itsaky.androidide.tooling.api.model.IdeGradleProject
import com.itsaky.androidide.tooling.api.util.ToolingApiLauncher
import com.itsaky.androidide.utils.ILogger
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
import java.io.BufferedReader
import java.io.File
import java.io.InputStream
import java.io.InputStreamReader
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
/** @author Akash Yadav */
@RunWith(JUnit4::class)
@@ -46,8 +46,9 @@ class ToolingApiImplTest {
val client = TestClient()
val server = launchServer(client)
val project = server.initialize(InitializeProjectMessage(getTestProject())).get()
log.debug(project?.asJson())
val result = server.initialize(InitializeProjectMessage(getTestProject())).get()
val project = result.project
log.debug(result.syncIssues.asJson())
assertThat(project).isNotNull()
assertThat(project!!).isInstanceOf(IdeGradleProject::class.java)
@@ -0,0 +1,24 @@
/*
* This file is part of AndroidIDE.
*
* AndroidIDE is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* AndroidIDE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
*/
package com.itsaky.androidide.tooling.api.model.internal
import com.android.builder.model.v2.models.ProjectSyncIssues
/** @author Akash Yadav */
class DefaultProjectSyncIssues(override val syncIssues: Collection<DefaultSyncIssue>) :
ProjectSyncIssues
@@ -0,0 +1,29 @@
/*
* This file is part of AndroidIDE.
*
* AndroidIDE is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* AndroidIDE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
*/
package com.itsaky.androidide.tooling.api.model.internal
import com.android.builder.model.v2.ide.SyncIssue
/** @author Akash Yadav */
class DefaultSyncIssue(
override val data: String?,
override val message: String,
override val multiLineMessage: List<String?>?,
override val severity: Int,
override val type: Int
) : SyncIssue
@@ -28,10 +28,12 @@ import com.android.builder.model.v2.ide.JavaArtifact
import com.android.builder.model.v2.ide.JavaCompileOptions
import com.android.builder.model.v2.ide.SourceProvider
import com.android.builder.model.v2.ide.SourceSetContainer
import com.android.builder.model.v2.ide.SyncIssue
import com.android.builder.model.v2.ide.TestInfo
import com.android.builder.model.v2.ide.TestedTargetVariant
import com.android.builder.model.v2.ide.Variant
import com.android.builder.model.v2.ide.ViewBindingOptions
import com.android.builder.model.v2.models.ProjectSyncIssues
import com.android.builder.model.v2.models.VariantDependencies
import com.itsaky.androidide.tooling.api.model.IdeAndroidModule
import com.itsaky.androidide.tooling.api.model.internal.DefaultAndroidArtifact
@@ -43,15 +45,16 @@ import com.itsaky.androidide.tooling.api.model.internal.DefaultGraphItem
import com.itsaky.androidide.tooling.api.model.internal.DefaultJavaArtifact
import com.itsaky.androidide.tooling.api.model.internal.DefaultJavaCompileOptions
import com.itsaky.androidide.tooling.api.model.internal.DefaultModelSyncFile
import com.itsaky.androidide.tooling.api.model.internal.DefaultProjectSyncIssues
import com.itsaky.androidide.tooling.api.model.internal.DefaultSourceProvider
import com.itsaky.androidide.tooling.api.model.internal.DefaultSourceSetContainer
import com.itsaky.androidide.tooling.api.model.internal.DefaultSyncIssue
import com.itsaky.androidide.tooling.api.model.internal.DefaultTestInfo
import com.itsaky.androidide.tooling.api.model.internal.DefaultTestedTargetVariant
import com.itsaky.androidide.tooling.api.model.internal.DefaultVariant
import com.itsaky.androidide.tooling.api.model.internal.DefaultVariantDependencies
import com.itsaky.androidide.tooling.api.model.internal.DefaultViewBindingOptions
import com.itsaky.androidide.utils.ILogger
import java.lang.reflect.Proxy
/**
* As the data is sent over streams, and the instances of properties specified in [IdeAndroidModule]
@@ -294,7 +297,7 @@ object AndroidModulePropertyCopier {
}
}
private fun copy(artifact: ArtifactDependencies?): DefaultArtifactDependencies? =
fun copy(artifact: ArtifactDependencies?): DefaultArtifactDependencies? =
DefaultArtifactDependencies().apply {
if (artifact == null) {
return null
@@ -304,7 +307,7 @@ object AndroidModulePropertyCopier {
this.runtimeDependencies = copy(artifact.runtimeDependencies)
}
private fun copy(graphs: List<GraphItem>?): List<DefaultGraphItem>? {
fun copy(graphs: List<GraphItem>?): List<DefaultGraphItem>? {
if (graphs == null) {
return null
}
@@ -312,9 +315,21 @@ object AndroidModulePropertyCopier {
return graphs.map { copy(it) }
}
private fun copy(graph: GraphItem): DefaultGraphItem =
fun copy(graph: GraphItem): DefaultGraphItem =
DefaultGraphItem().apply {
this.dependencies = copy(graph.dependencies)!!
this.requestedCoordinates = graph.requestedCoordinates
}
fun copy(issues: ProjectSyncIssues): DefaultProjectSyncIssues =
DefaultProjectSyncIssues(copy(issues.syncIssues))
@JvmName("copySyncIssue")
fun copy(syncIssues: Collection<SyncIssue>): Collection<DefaultSyncIssue> {
return syncIssues.map { copy(it) }
}
fun copy(issue: SyncIssue) =
DefaultSyncIssue(
issue.data, issue.message, issue.multiLineMessage, issue.severity, issue.type)
}
@@ -18,6 +18,7 @@
package com.itsaky.androidide.tooling.api
import com.itsaky.androidide.tooling.api.messages.InitializeProjectMessage
import com.itsaky.androidide.tooling.api.messages.result.InitializeResult
import com.itsaky.androidide.tooling.api.model.IdeGradleProject
import java.util.concurrent.*
import org.eclipse.lsp4j.jsonrpc.services.JsonRequest
@@ -33,7 +34,7 @@ interface IToolingApiServer {
/** Initialize the server with the project directory. */
@JsonRequest("initializeProject")
fun initialize(params: InitializeProjectMessage): CompletableFuture<IdeGradleProject?>
fun initialize(params: InitializeProjectMessage): CompletableFuture<InitializeResult>
/** Is the server initialized? */
@JsonRequest("isInitialized") fun isInitialized(): CompletableFuture<Boolean>
@@ -0,0 +1,34 @@
/*
* This file is part of AndroidIDE.
*
* AndroidIDE is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* AndroidIDE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
*/
package com.itsaky.androidide.tooling.api.messages.result
import com.itsaky.androidide.tooling.api.model.IdeGradleProject
import com.itsaky.androidide.tooling.api.model.internal.DefaultProjectSyncIssues
/**
* Result received after an initialize project request.
*
* @param project The initialized project model.
* @param syncIssues The issues reported by the Android Gradle Plugin during the project sync.
*
* @author Akash Yadav
*/
data class InitializeResult(
val project: IdeGradleProject?,
val syncIssues: Map<String, DefaultProjectSyncIssues>
)
@@ -0,0 +1,30 @@
/*
* This file is part of AndroidIDE.
*
* AndroidIDE is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* AndroidIDE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
*/
package com.itsaky.androidide.tooling.api.messages.result
import com.itsaky.androidide.tooling.api.model.IdeGradleTask
/**
* Result for a task execution.
*
* @param tasks The tasks that were executed.
* @param result The result of the task execution.
*
* @author Akash Yadav
*/
data class TaskExecutionResult(val tasks: List<IdeGradleTask>, val result: Boolean)
@@ -1,67 +0,0 @@
/*
* This file is part of AndroidIDE.
*
* AndroidIDE is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* AndroidIDE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
*/
package com.itsaky.androidide.tooling.api
import com.google.common.truth.Truth.assertThat
import com.google.gson.JsonObject
import com.google.gson.JsonParser
import com.itsaky.androidide.utils.ILogger
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
/** @author Akash Yadav */
@RunWith(JUnit4::class)
class MessageTest {
private val log = ILogger.newInstance(javaClass.simpleName)
@Test
fun testStringToMessage() {
val message =
"{'name': 'My name', 'otherName': 'Other other name', 'className': 'com.itsaky.androidide.tooling.api.MessageTest\$MessageToString'}"
val obj = Message.fromJson(message)
assertThat(obj).isInstanceOf(MessageToString::class.java)
assertThat((obj as MessageToString).name).isEqualTo("My name")
assertThat(obj.otherName).isEqualTo("Other other name")
log.debug("obj.name is ${obj.name}")
}
@Test
fun testMessageToString() {
val message = MessageToString()
val string = message.asJsonString()
log.debug("MessageToString:$string")
assertThat(string)
.isEqualTo(
"{\"name\":\"Your name\",\"otherName\":\"Other name\",\"className\":\"com.itsaky.androidide.tooling.api.MessageTest\$MessageToString\"}")
assertThat((JsonParser.parseString(string) as JsonObject)["name"].asString)
.isEqualTo("Your name")
assertThat((JsonParser.parseString(string) as JsonObject)["otherName"].asString)
.isEqualTo("Other name")
}
private open class Parent: Message() {
val otherName: String = "Other name"
}
private class MessageToString : Parent() {
val name: String = "Your name"
}
}