Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: migrating from the org.json Library to Gson #248

Merged
merged 15 commits into from
Jan 29, 2024
Merged
4 changes: 2 additions & 2 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ androidx-test-ext-junit = "1.1.5"

dropbox-differ = "0.0.1"
google-android-material = "1.5.0"
json = "20231013"
gson = "2.10.1"
junit = "4.13.2"
ktor-serialization-kotlinx-xml = "2.3.0"
squareup-okhttp = "5.0.0-alpha.11"
Expand Down Expand Up @@ -77,7 +77,7 @@ compose-ui-graphics-desktop = { module = "org.jetbrains.compose.ui:ui-graphics-d
compose-ui-test-junit4-desktop = { module = "org.jetbrains.compose.ui:ui-test-junit4-desktop", version.ref = "composeDesktop" }
dropbox-differ = { module = "com.dropbox.differ:differ", version.ref = "dropbox-differ" }
google-android-material = { module = "com.google.android.material:material", version.ref = "google-android-material" }
json = { module = "org.json:json", version.ref = "json" }
gson = { module = "com.google.code.gson:gson", version.ref = "gson"}
junit = { module = "junit:junit", version.ref = "junit" }
ktor-serialization-kotlinx-xml = { module = "io.ktor:ktor-serialization-kotlinx-xml", version.ref = "ktor-serialization-kotlinx-xml" }
squareup-okhttp = { module = "com.squareup.okhttp3:okhttp", version.ref = "squareup-okhttp" }
Expand Down
5 changes: 3 additions & 2 deletions include-build/roborazzi-core/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ kotlin {
}
commonJvmMain {
dependencies {
compileOnly libs.json
compileOnly libs.gson
api libs.dropbox.differ
implementation libs.junit
}
Expand All @@ -46,7 +46,7 @@ kotlin {
}
jvmMain {
dependencies {
implementation libs.json
implementation libs.gson
sanao1006 marked this conversation as resolved.
Show resolved Hide resolved
}
}
jvmTest {
Expand All @@ -61,6 +61,7 @@ kotlin {
compileOnly libs.androidx.compose.ui.test.junit4
api libs.androidx.test.espresso.core
implementation libs.androidx.core.ktx
implementation libs.gson
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,124 +1,105 @@
package com.github.takahirom.roborazzi

import com.github.takahirom.roborazzi.CaptureResults.Companion.gson
import com.google.gson.annotations.JsonAdapter
import com.google.gson.annotations.SerializedName
import java.io.File
import java.io.FileReader
import org.json.JSONObject

@JsonAdapter(CaptureResult.JsonAdapter::class)
sealed interface CaptureResult {
fun toJson(): JSONObject
val type: String
val timestampNs: Long
val compareFile: File?
val actualFile: File?
val goldenFile: File?

data class Recorded(
@SerializedName("golden_file_path")
override val goldenFile: File,
@SerializedName("timestamp")
override val timestampNs: Long,
) : CaptureResult {

override val type = "recorded"
override val actualFile: File?
get() = null
override val compareFile: File?
get() = null

override fun toJson(): JSONObject {
val json = JSONObject()
json.put("type", "recorded")
json.put("golden_file_path", goldenFile.absolutePath)
json.put("timestamp", timestampNs)
return json
}
}

data class Added(
@SerializedName("compare_file_path")
override val compareFile: File,
@SerializedName("actual_file_path")
override val actualFile: File,
@SerializedName("golden_file_path")
override val goldenFile: File,
@SerializedName("timestamp")
override val timestampNs: Long,
) : CaptureResult {
override fun toJson(): JSONObject {
val json = JSONObject()
json.put("type", "added")
json.put("compare_file_path", compareFile.absolutePath)
json.put("actual_file_path", actualFile.absolutePath)
json.put("golden_file_path", goldenFile.absolutePath)
json.put("timestamp", timestampNs)
return json
}
override val type = "added"
}

data class Changed(
@SerializedName("compare_file_path")
override val compareFile: File,
@SerializedName("golden_file_path")
override val goldenFile: File,
@SerializedName("actual_file_path")
override val actualFile: File,
@SerializedName("timestamp")
override val timestampNs: Long
) : CaptureResult {
override fun toJson(): JSONObject {
val json = JSONObject()
json.put("type", "changed")
json.put("compare_file_path", compareFile.absolutePath)
json.put("actual_file_path", actualFile.absolutePath)
json.put("golden_file_path", goldenFile.absolutePath)
json.put("timestamp", timestampNs)
return json
}
override val type = "changed"
}

data class Unchanged(
@SerializedName("golden_file_path")
override val goldenFile: File,
@SerializedName("timestamp")
override val timestampNs: Long
) : CaptureResult {
override val type = "unchanged"
override val actualFile: File?
get() = null
override val compareFile: File?
get() = null

override fun toJson(): JSONObject {
val json = JSONObject()
json.put("type", "unchanged")
json.put("golden_file_path", goldenFile.absolutePath)
json.put("timestamp", timestampNs)
return json
}
}

companion object {
fun fromJsonFile(inputPath: String): CaptureResult {
val json = JSONObject(FileReader(inputPath).readText())
return fromJson(json)
fun fromJsonFile(filePath: String): CaptureResult {
return gson.fromJson(FileReader(filePath), CaptureResult::class.java)
}
}

fun fromJson(json: JSONObject): CaptureResult {
val type = json.getString("type")
val compareFile = json.optString("compare_file_path")?.let { File(it) }
val goldenFile = json.optString("golden_file_path")?.let { File(it) }
val actualFile = json.optString("actual_file_path")?.let { File(it) }
val timestampNs = json.getLong("timestamp")
object JsonAdapter : com.google.gson.JsonSerializer<CaptureResult>,
com.google.gson.JsonDeserializer<CaptureResult> {
override fun serialize(
src: CaptureResult,
typeOfSrc: java.lang.reflect.Type,
context: com.google.gson.JsonSerializationContext
): com.google.gson.JsonElement {
val jsonElement = when (src) {
is Recorded -> context.serialize(src, Recorded::class.java)
is Changed -> context.serialize(src, Changed::class.java)
is Unchanged -> context.serialize(src, Unchanged::class.java)
is Added -> context.serialize(src, Added::class.java)
}
return jsonElement
}

override fun deserialize(
json: com.google.gson.JsonElement,
typeOfT: java.lang.reflect.Type,
context: com.google.gson.JsonDeserializationContext
): CaptureResult? {
val type = requireNotNull(json.asJsonObject.get("type")?.asString)
return when (type) {
"recorded" -> Recorded(
goldenFile = goldenFile!!,
timestampNs = timestampNs
)

"changed" -> Changed(
compareFile = compareFile!!,
goldenFile = goldenFile!!,
actualFile = actualFile!!,
timestampNs = timestampNs
)

"unchanged" -> Unchanged(
goldenFile = goldenFile!!,
timestampNs = timestampNs
)

"added" -> Added(
compareFile = compareFile!!,
actualFile = actualFile!!,
timestampNs = timestampNs,
goldenFile = goldenFile!!,
)

"recorded" -> context.deserialize(json, Recorded::class.java)
"changed" -> context.deserialize(json, Changed::class.java)
"unchanged" -> context.deserialize(json, Unchanged::class.java)
"added" -> context.deserialize(json, Added::class.java)
else -> throw IllegalArgumentException("Unknown type $type")
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,22 +1,20 @@
package com.github.takahirom.roborazzi

import org.json.JSONArray
import org.json.JSONObject
import com.google.gson.*
import com.google.gson.annotations.SerializedName
import java.io.File
import java.io.FileReader
import java.lang.reflect.Type

data class CaptureResults(
val summary: ResultSummary,
@SerializedName("summary")
val resultSummary: ResultSummary,
@SerializedName("results")
val captureResults: List<CaptureResult>
) {
fun toJson(): JSONObject {
val json = JSONObject()
json.put("summary", summary.toJson())
val resultsArray = JSONArray()
captureResults.forEach { result ->
resultsArray.put(result.toJson())
}
json.put("results", resultsArray)
return json

fun toJson(): String {
return gson.toJson(this)
}

fun toHtml(reportDirectoryPath: String): String {
Expand Down Expand Up @@ -78,7 +76,7 @@ data class CaptureResults(
}
}
return buildString {
append(summary.toHtml())
append(resultSummary.toHtml())
append(buildTable("Recorded images", "recorded", recordedImages))
append(buildTable("Added images", "added", addedImages))
append(buildTable("Changed images", "changed", changedImages))
Expand All @@ -87,26 +85,33 @@ data class CaptureResults(
}

companion object {
val gson: Gson = GsonBuilder()
.registerTypeAdapter(File::class.java, object : JsonSerializer<File>, JsonDeserializer<File> {
override fun serialize(src: File?, typeOfSrc: Type?, context: JsonSerializationContext?): JsonElement {
val absolutePath = src?.absolutePath ?: return JsonNull.INSTANCE
return JsonPrimitive(absolutePath)
}

override fun deserialize(json: JsonElement?, typeOfT: Type?, context: JsonDeserializationContext?): File {
val path = json?.asString ?: throw JsonParseException("File path is null")
return File(path)
}
})
.create()

fun fromJsonFile(inputPath: String): CaptureResults {
val fileContents = File(inputPath).readText()
val jsonObject = JSONObject(fileContents)
val jsonObject = JsonParser.parseString(FileReader(inputPath).readText()).asJsonObject
return fromJson(jsonObject)
}

fun fromJson(jsonObject: JSONObject): CaptureResults {
val summary = ResultSummary.fromJson(jsonObject.getJSONObject("summary"))
val resultsArray = jsonObject.getJSONArray("results")
val captureResults = mutableListOf<CaptureResult>()
for (i in 0 until resultsArray.length()) {
val resultJson = resultsArray.getJSONObject(i)
captureResults.add(CaptureResult.fromJson(resultJson))
}
return CaptureResults(summary, captureResults)
fun fromJson(jsonObject: JsonObject): CaptureResults {
// Auto convert using Gson
return gson.fromJson(jsonObject, CaptureResults::class.java)
}

fun from(results: List<CaptureResult>): CaptureResults {
return CaptureResults(
summary = ResultSummary(
resultSummary = ResultSummary(
total = results.size,
recorded = results.count { it is CaptureResult.Recorded },
added = results.count { it is CaptureResult.Added },
Expand Down
Original file line number Diff line number Diff line change
@@ -1,24 +1,12 @@
package com.github.takahirom.roborazzi

import org.json.JSONObject

data class ResultSummary(
val total: Int,
val recorded: Int,
val added: Int,
val changed: Int,
val unchanged: Int
) {
fun toJson(): JSONObject {
val json = JSONObject()
json.put("total", total)
json.put("recorded", recorded)
json.put("added", added)
json.put("changed", changed)
json.put("unchanged", unchanged)
return json
}

fun toHtml(): String {
return """
<h3>Summary</h3>
Expand All @@ -44,21 +32,4 @@ data class ResultSummary(
</table>
""".trimIndent()
}

companion object {
fun fromJson(jsonObject: JSONObject): ResultSummary {
val total = jsonObject.getInt("total")
val recorded = jsonObject.getInt("recorded")
val added = jsonObject.getInt("added")
val changed = jsonObject.getInt("changed")
val unchanged = jsonObject.getInt("unchanged")
return ResultSummary(
total = total,
recorded = recorded,
added = added,
changed = changed,
unchanged = unchanged
)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package com.github.takahirom.roborazzi

import com.dropbox.differ.ImageComparator
import com.dropbox.differ.SimpleImageComparator
import com.github.takahirom.roborazzi.CaptureResults.Companion.gson
import java.io.File
import java.io.FileWriter

Expand Down Expand Up @@ -241,7 +242,7 @@ data class RoborazziOptions(
val reportFileName =
"$absolutePath/${captureResult.timestampNs}_$nameWithoutExtension.json"

val jsonResult = captureResult.toJson()
val jsonResult = gson.toJson(captureResult)
FileWriter(reportFileName).use { it.write(jsonResult.toString()) }
debugLog { "JsonResult file($reportFileName) has been written" }
}
Expand Down
Loading
Loading