diff --git a/.github/workflows/pull-request-merge-check.yml b/.github/workflows/pull-request-merge-check.yml index 7d1a26f2..86dd05bf 100644 --- a/.github/workflows/pull-request-merge-check.yml +++ b/.github/workflows/pull-request-merge-check.yml @@ -236,14 +236,14 @@ jobs: - name: Run Kover uses: gradle/gradle-build-action@v2.8.1 with: - arguments: koverXmlReport -x integrationTest -x e2eTest + arguments: koverXmlReport -x integrationTest -x e2eTest --rerun-tasks - name: Add coverage report to PR if: always() id: kover - uses: mi-kas/kover-report@v1 + uses: madrapps/jacoco-report@v1.6.1 with: - path: | + paths: | ${{ github.workspace }}/build/reports/kover/report.xml token: ${{ secrets.GITHUB_TOKEN }} title: Code Coverage diff --git a/build.gradle.kts b/build.gradle.kts index 9c892615..18d64acb 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -83,7 +83,9 @@ tasks.withType { useJUnitPlatform() doFirst { jvmArgs = arrayOf( - "--add-opens", "java.base/java.lang=ALL-UNNAMED" + "--add-opens", "java.base/java.lang=ALL-UNNAMED", + "--add-opens", "java.base/java.util=ALL-UNNAMED", + "--add-opens", "java.naming/javax.naming=ALL-UNNAMED", ).toMutableList() } } diff --git a/src/main/kotlin/dev/usbharu/hideout/activitypub/domain/model/Delete.kt b/src/main/kotlin/dev/usbharu/hideout/activitypub/domain/model/Delete.kt index 6f691492..61ffb348 100644 --- a/src/main/kotlin/dev/usbharu/hideout/activitypub/domain/model/Delete.kt +++ b/src/main/kotlin/dev/usbharu/hideout/activitypub/domain/model/Delete.kt @@ -50,6 +50,13 @@ open class Delete : Object, HasId, HasActor { return result } - override fun toString(): String = - "Delete(`object`=$apObject, published=$published, actor='$actor', id='$id') ${super.toString()}" + override fun toString(): String { + return "Delete(" + + "apObject=$apObject, " + + "published='$published', " + + "actor='$actor', " + + "id='$id'" + + ")" + + " ${super.toString()}" + } } diff --git a/src/main/kotlin/dev/usbharu/hideout/activitypub/domain/model/Emoji.kt b/src/main/kotlin/dev/usbharu/hideout/activitypub/domain/model/Emoji.kt index 37ebb879..2b9a0bee 100644 --- a/src/main/kotlin/dev/usbharu/hideout/activitypub/domain/model/Emoji.kt +++ b/src/main/kotlin/dev/usbharu/hideout/activitypub/domain/model/Emoji.kt @@ -14,21 +14,37 @@ open class Emoji( HasName, HasId { + override fun toString(): String { + return "Emoji(" + + "name='$name', " + + "id='$id', " + + "updated='$updated', " + + "icon=$icon" + + ")" + + " ${super.toString()}" + } + override fun equals(other: Any?): Boolean { if (this === other) return true - if (other !is Emoji) return false + if (javaClass != other?.javaClass) return false if (!super.equals(other)) return false + other as Emoji + + if (name != other.name) return false + if (id != other.id) return false if (updated != other.updated) return false - return icon == other.icon + if (icon != other.icon) return false + + return true } override fun hashCode(): Int { var result = super.hashCode() + result = 31 * result + name.hashCode() + result = 31 * result + id.hashCode() result = 31 * result + updated.hashCode() result = 31 * result + icon.hashCode() return result } - - override fun toString(): String = "Emoji(updated=$updated, icon=$icon) ${super.toString()}" } diff --git a/src/main/kotlin/dev/usbharu/hideout/activitypub/domain/model/Follow.kt b/src/main/kotlin/dev/usbharu/hideout/activitypub/domain/model/Follow.kt index c7f292ba..8a0382a9 100644 --- a/src/main/kotlin/dev/usbharu/hideout/activitypub/domain/model/Follow.kt +++ b/src/main/kotlin/dev/usbharu/hideout/activitypub/domain/model/Follow.kt @@ -32,5 +32,11 @@ open class Follow( return result } - override fun toString(): String = "Follow(`object`=$apObject, actor='$actor') ${super.toString()}" + override fun toString(): String { + return "Follow(" + + "apObject='$apObject', " + + "actor='$actor'" + + ")" + + " ${super.toString()}" + } } diff --git a/src/main/kotlin/dev/usbharu/hideout/activitypub/domain/model/Undo.kt b/src/main/kotlin/dev/usbharu/hideout/activitypub/domain/model/Undo.kt index b1399777..178373fd 100644 --- a/src/main/kotlin/dev/usbharu/hideout/activitypub/domain/model/Undo.kt +++ b/src/main/kotlin/dev/usbharu/hideout/activitypub/domain/model/Undo.kt @@ -38,6 +38,13 @@ open class Undo( return result } - override fun toString(): String = - "Undo(`object`=$apObject, published=$published, actor='$actor', id='$id') ${super.toString()}" + override fun toString(): String { + return "Undo(" + + "actor='$actor', " + + "id='$id', " + + "apObject=$apObject, " + + "published='$published'" + + ")" + + " ${super.toString()}" + } } diff --git a/src/main/kotlin/dev/usbharu/hideout/activitypub/service/common/APResourceResolveServiceImpl.kt b/src/main/kotlin/dev/usbharu/hideout/activitypub/service/common/APResourceResolveServiceImpl.kt index ad24ec57..246b02d8 100644 --- a/src/main/kotlin/dev/usbharu/hideout/activitypub/service/common/APResourceResolveServiceImpl.kt +++ b/src/main/kotlin/dev/usbharu/hideout/activitypub/service/common/APResourceResolveServiceImpl.kt @@ -73,5 +73,18 @@ class APResourceResolveServiceImpl( override suspend fun statusMessage(): String { TODO("Not yet implemented") } + + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (javaClass != other?.javaClass) return false + + other as APResolveResponse<*> + + return objects == other.objects + } + + override fun hashCode(): Int { + return objects.hashCode() + } } } diff --git a/src/main/kotlin/dev/usbharu/hideout/application/service/id/SnowflakeIdGenerateService.kt b/src/main/kotlin/dev/usbharu/hideout/application/service/id/SnowflakeIdGenerateService.kt index dc5ab4bc..54288173 100644 --- a/src/main/kotlin/dev/usbharu/hideout/application/service/id/SnowflakeIdGenerateService.kt +++ b/src/main/kotlin/dev/usbharu/hideout/application/service/id/SnowflakeIdGenerateService.kt @@ -43,4 +43,25 @@ open class SnowflakeIdGenerateService(private val baseTime: Long) : IdGenerateSe } private fun getTime(): Long = Instant.now().toEpochMilli() + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (javaClass != other?.javaClass) return false + + other as SnowflakeIdGenerateService + + if (baseTime != other.baseTime) return false + if (lastTimeStamp != other.lastTimeStamp) return false + if (sequenceId != other.sequenceId) return false + if (mutex != other.mutex) return false + + return true + } + + override fun hashCode(): Int { + var result = baseTime.hashCode() + result = 31 * result + lastTimeStamp.hashCode() + result = 31 * result + sequenceId + result = 31 * result + mutex.hashCode() + return result + } } diff --git a/src/main/kotlin/dev/usbharu/hideout/core/domain/model/actor/Actor.kt b/src/main/kotlin/dev/usbharu/hideout/core/domain/model/actor/Actor.kt index 3833e71a..6689e542 100644 --- a/src/main/kotlin/dev/usbharu/hideout/core/domain/model/actor/Actor.kt +++ b/src/main/kotlin/dev/usbharu/hideout/core/domain/model/actor/Actor.kt @@ -184,22 +184,26 @@ data class Actor private constructor( override fun toString(): String { return "Actor(" + - "id=$id, " + - "name='$name', " + - "domain='$domain', " + - "screenName='$screenName', " + - "description='$description', " + - "inbox='$inbox', " + - "outbox='$outbox', " + - "url='$url', " + - "publicKey='$publicKey', " + - "privateKey=$privateKey, " + - "createdAt=$createdAt, " + - "keyId='$keyId', " + - "followers=$followers, " + - "following=$following, " + - "instance=$instance, " + - "locked=$locked" + - ")" + "id=$id, " + + "name='$name', " + + "domain='$domain', " + + "screenName='$screenName', " + + "description='$description', " + + "inbox='$inbox', " + + "outbox='$outbox', " + + "url='$url', " + + "publicKey='$publicKey', " + + "privateKey=$privateKey, " + + "createdAt=$createdAt, " + + "keyId='$keyId', " + + "followers=$followers, " + + "following=$following, " + + "instance=$instance, " + + "locked=$locked, " + + "followersCount=$followersCount, " + + "followingCount=$followingCount, " + + "postsCount=$postsCount, " + + "lastPostDate=$lastPostDate" + + ")" } } diff --git a/src/main/kotlin/dev/usbharu/hideout/core/domain/model/instance/Nodeinfo.kt b/src/main/kotlin/dev/usbharu/hideout/core/domain/model/instance/Nodeinfo.kt index f7fc3160..e2e44267 100644 --- a/src/main/kotlin/dev/usbharu/hideout/core/domain/model/instance/Nodeinfo.kt +++ b/src/main/kotlin/dev/usbharu/hideout/core/domain/model/instance/Nodeinfo.kt @@ -3,9 +3,38 @@ package dev.usbharu.hideout.core.domain.model.instance class Nodeinfo private constructor() { var links: List = emptyList() + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (javaClass != other?.javaClass) return false + + other as Nodeinfo + + return links == other.links + } + + override fun hashCode(): Int { + return links.hashCode() + } } class Links private constructor() { var rel: String? = null var href: String? = null + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (javaClass != other?.javaClass) return false + + other as Links + + if (rel != other.rel) return false + if (href != other.href) return false + + return true + } + + override fun hashCode(): Int { + var result = rel?.hashCode() ?: 0 + result = 31 * result + (href?.hashCode() ?: 0) + return result + } } diff --git a/src/main/kotlin/dev/usbharu/hideout/core/domain/model/instance/Nodeinfo2_0.kt b/src/main/kotlin/dev/usbharu/hideout/core/domain/model/instance/Nodeinfo2_0.kt index 97478228..f3f5f72e 100644 --- a/src/main/kotlin/dev/usbharu/hideout/core/domain/model/instance/Nodeinfo2_0.kt +++ b/src/main/kotlin/dev/usbharu/hideout/core/domain/model/instance/Nodeinfo2_0.kt @@ -6,14 +6,66 @@ package dev.usbharu.hideout.core.domain.model.instance class Nodeinfo2_0 { var metadata: Metadata? = null var software: Software? = null + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (javaClass != other?.javaClass) return false + + other as Nodeinfo2_0 + + if (metadata != other.metadata) return false + if (software != other.software) return false + + return true + } + + override fun hashCode(): Int { + var result = metadata?.hashCode() ?: 0 + result = 31 * result + (software?.hashCode() ?: 0) + return result + } } class Metadata { var nodeName: String? = null var nodeDescription: String? = null + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (javaClass != other?.javaClass) return false + + other as Metadata + + if (nodeName != other.nodeName) return false + if (nodeDescription != other.nodeDescription) return false + + return true + } + + override fun hashCode(): Int { + var result = nodeName?.hashCode() ?: 0 + result = 31 * result + (nodeDescription?.hashCode() ?: 0) + return result + } } class Software { var name: String? = null var version: String? = null + + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (javaClass != other?.javaClass) return false + + other as Software + + if (name != other.name) return false + if (version != other.version) return false + + return true + } + + override fun hashCode(): Int { + var result = name?.hashCode() ?: 0 + result = 31 * result + (version?.hashCode() ?: 0) + return result + } } diff --git a/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/springframework/httpsignature/HttpSignatureUser.kt b/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/springframework/httpsignature/HttpSignatureUser.kt index 8beb4513..2d546af0 100644 --- a/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/springframework/httpsignature/HttpSignatureUser.kt +++ b/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/springframework/httpsignature/HttpSignatureUser.kt @@ -39,6 +39,14 @@ class HttpSignatureUser( return result } + override fun toString(): String { + return "HttpSignatureUser(" + + "domain='$domain', " + + "id=$id" + + ")" + + " ${super.toString()}" + } + companion object { @Serial private const val serialVersionUID: Long = -3330552099960982997L diff --git a/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/springframework/httpsignature/HttpSignatureVerifierComposite.kt b/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/springframework/httpsignature/HttpSignatureVerifierComposite.kt index a1203ca1..4496e0b5 100644 --- a/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/springframework/httpsignature/HttpSignatureVerifierComposite.kt +++ b/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/springframework/httpsignature/HttpSignatureVerifierComposite.kt @@ -19,4 +19,22 @@ class HttpSignatureVerifierComposite( throw IllegalArgumentException("Unsupported algorithm. ${signature.algorithm}") } + + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (javaClass != other?.javaClass) return false + + other as HttpSignatureVerifierComposite + + if (map != other.map) return false + if (httpSignatureHeaderParser != other.httpSignatureHeaderParser) return false + + return true + } + + override fun hashCode(): Int { + var result = map.hashCode() + result = 31 * result + httpSignatureHeaderParser.hashCode() + return result + } } diff --git a/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/springframework/oauth2/UserDetailsImpl.kt b/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/springframework/oauth2/UserDetailsImpl.kt index 92b007da..cb06f2ce 100644 --- a/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/springframework/oauth2/UserDetailsImpl.kt +++ b/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/springframework/oauth2/UserDetailsImpl.kt @@ -30,6 +30,29 @@ class UserDetailsImpl( @Serial private const val serialVersionUID: Long = -899168205656607781L } + + override fun toString(): String { + return "UserDetailsImpl(" + + "id=$id" + + ")" + + " ${super.toString()}" + } + + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (javaClass != other?.javaClass) return false + if (!super.equals(other)) return false + + other as UserDetailsImpl + + return id == other.id + } + + override fun hashCode(): Int { + var result = super.hashCode() + result = 31 * result + id.hashCode() + return result + } } @JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY) diff --git a/src/main/kotlin/dev/usbharu/hideout/core/service/media/SavedMedia.kt b/src/main/kotlin/dev/usbharu/hideout/core/service/media/SavedMedia.kt index 4f644da5..50a2caac 100644 --- a/src/main/kotlin/dev/usbharu/hideout/core/service/media/SavedMedia.kt +++ b/src/main/kotlin/dev/usbharu/hideout/core/service/media/SavedMedia.kt @@ -1,16 +1,73 @@ package dev.usbharu.hideout.core.service.media -sealed class SavedMedia(val success: Boolean) +sealed class SavedMedia(val success: Boolean) { + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (javaClass != other?.javaClass) return false + + other as SavedMedia + + return success == other.success + } + + override fun hashCode(): Int { + return success.hashCode() + } +} class SuccessSavedMedia( val name: String, val url: String, val thumbnailUrl: String, ) : - SavedMedia(true) + SavedMedia(true) { + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (javaClass != other?.javaClass) return false + if (!super.equals(other)) return false + + other as SuccessSavedMedia + + if (name != other.name) return false + if (url != other.url) return false + if (thumbnailUrl != other.thumbnailUrl) return false + + return true + } + + override fun hashCode(): Int { + var result = super.hashCode() + result = 31 * result + name.hashCode() + result = 31 * result + url.hashCode() + result = 31 * result + thumbnailUrl.hashCode() + return result + } +} class FaildSavedMedia( val reason: String, val description: String, val trace: Throwable? = null -) : SavedMedia(false) +) : SavedMedia(false) { + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (javaClass != other?.javaClass) return false + if (!super.equals(other)) return false + + other as FaildSavedMedia + + if (reason != other.reason) return false + if (description != other.description) return false + if (trace != other.trace) return false + + return true + } + + override fun hashCode(): Int { + var result = super.hashCode() + result = 31 * result + reason.hashCode() + result = 31 * result + description.hashCode() + result = 31 * result + (trace?.hashCode() ?: 0) + return result + } +} diff --git a/src/main/kotlin/dev/usbharu/hideout/core/service/resource/KtorResolveResponse.kt b/src/main/kotlin/dev/usbharu/hideout/core/service/resource/KtorResolveResponse.kt index 3a5e2ad1..66b8ba85 100644 --- a/src/main/kotlin/dev/usbharu/hideout/core/service/resource/KtorResolveResponse.kt +++ b/src/main/kotlin/dev/usbharu/hideout/core/service/resource/KtorResolveResponse.kt @@ -28,4 +28,23 @@ class KtorResolveResponse(val ktorHttpResponse: HttpResponse) : ResolveResponse override suspend fun header(): Map> = ktorHttpResponse.headers.toMap() override suspend fun status(): Int = ktorHttpResponse.status.value override suspend fun statusMessage(): String = ktorHttpResponse.status.description + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (javaClass != other?.javaClass) return false + + other as KtorResolveResponse + + if (ktorHttpResponse != other.ktorHttpResponse) return false + if (_bodyAsText != other._bodyAsText) return false + if (!_bodyAsBytes.contentEquals(other._bodyAsBytes)) return false + + return true + } + + override fun hashCode(): Int { + var result = ktorHttpResponse.hashCode() + result = 31 * result + _bodyAsText.hashCode() + result = 31 * result + _bodyAsBytes.contentHashCode() + return result + } } diff --git a/src/main/kotlin/dev/usbharu/hideout/mastodon/interfaces/api/status/StatusesRequest.kt b/src/main/kotlin/dev/usbharu/hideout/mastodon/interfaces/api/status/StatusesRequest.kt index 98803f6b..0a9fac65 100644 --- a/src/main/kotlin/dev/usbharu/hideout/mastodon/interfaces/api/status/StatusesRequest.kt +++ b/src/main/kotlin/dev/usbharu/hideout/mastodon/interfaces/api/status/StatusesRequest.kt @@ -65,9 +65,17 @@ class StatusesRequest { } override fun toString(): String { - return "StatusesRequest(status=$status, mediaIds=$media_ids, poll=$poll, inReplyToId=$in_reply_to_id, " + - "sensitive=$sensitive, spoilerText=$spoiler_text, visibility=$visibility, language=$language," + - " scheduledAt=$scheduled_at)" + return "StatusesRequest(" + + "status=$status, " + + "media_ids=$media_ids, " + + "poll=$poll, " + + "in_reply_to_id=$in_reply_to_id, " + + "sensitive=$sensitive, " + + "spoiler_text=$spoiler_text, " + + "visibility=$visibility, " + + "language=$language, " + + "scheduled_at=$scheduled_at" + + ")" } @Suppress("EnumNaming", "EnumEntryNameCase") diff --git a/src/main/kotlin/dev/usbharu/hideout/util/LruCache.kt b/src/main/kotlin/dev/usbharu/hideout/util/LruCache.kt index 3f65175a..77c891da 100644 --- a/src/main/kotlin/dev/usbharu/hideout/util/LruCache.kt +++ b/src/main/kotlin/dev/usbharu/hideout/util/LruCache.kt @@ -5,6 +5,12 @@ import java.io.Serial class LruCache(private val maxSize: Int) : LinkedHashMap(15, 0.75f, true) { override fun removeEldestEntry(eldest: MutableMap.MutableEntry?): Boolean = size > maxSize + override fun toString(): String { + return "LruCache(" + + "maxSize=$maxSize" + + ")" + + " ${super.toString()}" + } companion object { @Serial diff --git a/src/main/kotlin/dev/usbharu/hideout/util/TempFileUtil.kt b/src/main/kotlin/dev/usbharu/hideout/util/TempFileUtil.kt index 186aa889..8a506767 100644 --- a/src/main/kotlin/dev/usbharu/hideout/util/TempFileUtil.kt +++ b/src/main/kotlin/dev/usbharu/hideout/util/TempFileUtil.kt @@ -9,4 +9,17 @@ class TempFile(val path: T) : AutoCloseable { override fun close() { path?.let { Files.deleteIfExists(it) } } + + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (javaClass != other?.javaClass) return false + + other as TempFile<*> + + return path == other.path + } + + override fun hashCode(): Int { + return path?.hashCode() ?: 0 + } } diff --git a/src/test/kotlin/dev/usbharu/hideout/EqualsAndToStringTest.kt b/src/test/kotlin/dev/usbharu/hideout/EqualsAndToStringTest.kt index 62f68093..11360eb6 100644 --- a/src/test/kotlin/dev/usbharu/hideout/EqualsAndToStringTest.kt +++ b/src/test/kotlin/dev/usbharu/hideout/EqualsAndToStringTest.kt @@ -1,41 +1,111 @@ package dev.usbharu.hideout +import com.fasterxml.jackson.module.kotlin.isKotlinClass import com.jparams.verifier.tostring.ToStringVerifier +import com.jparams.verifier.tostring.preset.Presets import nl.jqno.equalsverifier.EqualsVerifier import nl.jqno.equalsverifier.Warning import nl.jqno.equalsverifier.internal.reflection.PackageScanner -import org.junit.jupiter.api.Test +import org.junit.jupiter.api.DynamicTest +import org.junit.jupiter.api.DynamicTest.dynamicTest +import org.junit.jupiter.api.TestFactory +import org.springframework.context.annotation.Configuration +import org.springframework.stereotype.Component +import org.springframework.stereotype.Controller +import org.springframework.stereotype.Repository +import org.springframework.stereotype.Service +import org.springframework.web.bind.annotation.RestController import java.lang.reflect.Modifier -import kotlin.test.assertFails class EqualsAndToStringTest { - @Test - fun equalsTest() { - assertFails { - EqualsVerifier - .simple() - .suppress(Warning.INHERITED_DIRECTLY_FROM_OBJECT) - .forPackage("dev.usbharu.hideout", true) - .verify() - } + @TestFactory + fun equalsTest(): List { + + val classes = PackageScanner.getClassesIn("dev.usbharu.hideout", null, true) + + return classes + .asSequence() + .filter { + it.getAnnotation(Service::class.java) == null + } + .filter { + it.getAnnotation(Repository::class.java) == null + } + .filter { + it.getAnnotation(Component::class.java) == null + } + .filter { + it.getAnnotation(Controller::class.java) == null + } + .filter { + it.getAnnotation(RestController::class.java) == null + } + .filter { + it.getAnnotation(Configuration::class.java) == null + } + .filterNot { + it.packageName.startsWith("dev.usbharu.hideout.domain.mastodon.model.generated") + } + .filterNot { + Throwable::class.java.isAssignableFrom(it) + } + .filterNot { + Modifier.isAbstract(it.modifiers) + } + .filter { + try { + it.kotlin.objectInstance == null + } catch (_: Exception) { + true + } + + } + .filter { + it.superclass == Any::class.java || it.superclass?.packageName?.startsWith("dev.usbharu") ?: true + } + .map { + dynamicTest(it.name) { + if (it.isKotlinClass()) { + println(" at ${it.name}.toString(${it.simpleName}.kt:1)") + } + try { + EqualsVerifier.simple() + .suppress(Warning.INHERITED_DIRECTLY_FROM_OBJECT, Warning.TRANSIENT_FIELDS) + .forClass(it) + .verify() + } catch (e: AssertionError) { + e.printStackTrace() + } + } + } + .toList() } - @Test - fun toStringTest() { + @TestFactory + fun toStringTest(): List { - PackageScanner.getClassesIn("dev.usbharu.hideout", null, true) + return PackageScanner.getClassesIn("dev.usbharu.hideout", null, true) .filter { it != null && !it.isEnum && !it.isInterface && !Modifier.isAbstract(it.modifiers) } - .forEach { - try { - ToStringVerifier.forClass(it).verify() - } catch (e: AssertionError) { - println(it.name) - e.printStackTrace() - } catch (e: Exception) { - println(it.name) - e.printStackTrace() + .filter { + val clazz = it.getMethod(it::toString.name).declaringClass + clazz != Any::class.java && clazz != Throwable::class.java + } + .filter { + it.superclass == Any::class.java || it.superclass?.packageName?.startsWith("dev.usbharu") ?: true + } + .map { + + dynamicTest(it.name) { + if (it.isKotlinClass()) { + println(" at ${it.name}.toString(${it.simpleName}.kt:1)") + } + try { + ToStringVerifier.forClass(it).withPreset(Presets.INTELLI_J).verify() + } catch (e: Exception) { + e.printStackTrace() + } } } } diff --git a/src/test/kotlin/dev/usbharu/hideout/activitypub/domain/model/CreateTest.kt b/src/test/kotlin/dev/usbharu/hideout/activitypub/domain/model/CreateTest.kt new file mode 100644 index 00000000..1baf4e45 --- /dev/null +++ b/src/test/kotlin/dev/usbharu/hideout/activitypub/domain/model/CreateTest.kt @@ -0,0 +1,83 @@ +package dev.usbharu.hideout.activitypub.domain.model + +import com.fasterxml.jackson.module.kotlin.readValue +import dev.usbharu.hideout.application.config.ActivityPubConfig +import org.intellij.lang.annotations.Language +import org.junit.jupiter.api.Test + +class CreateTest { + @Test + fun Createのデイシリアライズができる() { + @Language("JSON") val json = """{ + "@context": [ + "https://www.w3.org/ns/activitystreams", + "https://w3id.org/security/v1", + { + "manuallyApprovesFollowers": "as:manuallyApprovesFollowers", + "sensitive": "as:sensitive", + "Hashtag": "as:Hashtag", + "quoteUrl": "as:quoteUrl", + "toot": "http://joinmastodon.org/ns#", + "Emoji": "toot:Emoji", + "featured": "toot:featured", + "discoverable": "toot:discoverable", + "schema": "http://schema.org#", + "PropertyValue": "schema:PropertyValue", + "value": "schema:value", + "misskey": "https://misskey-hub.net/ns#", + "_misskey_content": "misskey:_misskey_content", + "_misskey_quote": "misskey:_misskey_quote", + "_misskey_reaction": "misskey:_misskey_reaction", + "_misskey_votes": "misskey:_misskey_votes", + "isCat": "misskey:isCat", + "vcard": "http://www.w3.org/2006/vcard/ns#" + } + ], + "id": "https://misskey.usbharu.dev/notes/9f2i9cm88e/activity", + "actor": "https://misskey.usbharu.dev/users/97ws8y3rj6", + "type": "Create", + "published": "2023-05-22T14:26:53.600Z", + "object": { + "id": "https://misskey.usbharu.dev/notes/9f2i9cm88e", + "type": "Note", + "attributedTo": "https://misskey.usbharu.dev/users/97ws8y3rj6", + "content": "

@trapezial@calckey.jp いやそういうことじゃなくて、連合先と自インスタンスで状態が狂うことが多いのでどっちに合わせるべきかと…

", + "_misskey_content": "@trapezial@calckey.jp いやそういうことじゃなくて、連合先と自インスタンスで状態が狂うことが多いのでどっちに合わせるべきかと…", + "source": { + "content": "@trapezial@calckey.jp いやそういうことじゃなくて、連合先と自インスタンスで状態が狂うことが多いのでどっちに合わせるべきかと…", + "mediaType": "text/x.misskeymarkdown" + }, + "published": "2023-05-22T14:26:53.600Z", + "to": [ + "https://misskey.usbharu.dev/users/97ws8y3rj6/followers" + ], + "cc": [ + "https://www.w3.org/ns/activitystreams#Public", + "https://calckey.jp/users/9bu1xzwjyb" + ], + "inReplyTo": "https://calckey.jp/notes/9f2i7ymf1d", + "attachment": [], + "sensitive": false, + "tag": [ + { + "type": "Mention", + "href": "https://calckey.jp/users/9bu1xzwjyb", + "name": "@trapezial@calckey.jp" + } + ] + }, + "to": [ + "https://misskey.usbharu.dev/users/97ws8y3rj6/followers" + ], + "cc": [ + "https://www.w3.org/ns/activitystreams#Public", + "https://calckey.jp/users/9bu1xzwjyb" + ] +} +""" + + val objectMapper = ActivityPubConfig().objectMapper() + + objectMapper.readValue(json) + } +} diff --git a/src/test/kotlin/dev/usbharu/hideout/activitypub/domain/model/DocumentTest.kt b/src/test/kotlin/dev/usbharu/hideout/activitypub/domain/model/DocumentTest.kt new file mode 100644 index 00000000..5257d8e8 --- /dev/null +++ b/src/test/kotlin/dev/usbharu/hideout/activitypub/domain/model/DocumentTest.kt @@ -0,0 +1,37 @@ +package dev.usbharu.hideout.activitypub.domain.model + +import com.fasterxml.jackson.module.kotlin.readValue +import dev.usbharu.hideout.application.config.ActivityPubConfig +import org.intellij.lang.annotations.Language +import org.junit.jupiter.api.Test + +class DocumentTest { + @Test + fun Documentをデシリアライズできる() { + @Language("JSON") val json = """{ + "type": "Document", + "mediaType": "image/webp", + "url": "https://s3misskey.usbharu.dev/misskey-minio/misskey-minio/data/81ec9ad1-2581-466e-b90c-d9d2350ab95c.webp", + "name": "ALTテスト" + }""" + + val objectMapper = ActivityPubConfig().objectMapper() + + objectMapper.readValue(json) + } + + @Test + fun nameがnullなDocumentのデイシリアライズができる() { + //language=JSON + val json = """{ + "type": "Document", + "mediaType": "image/webp", + "url": "https://s3misskey.usbharu.dev/misskey-minio/misskey-minio/data/81ec9ad1-2581-466e-b90c-d9d2350ab95c.webp", + "name": null + }""" + + val objectMapper = ActivityPubConfig().objectMapper() + + objectMapper.readValue(json) + } +} diff --git a/src/test/kotlin/dev/usbharu/hideout/activitypub/domain/model/PersonSerializeTest.kt b/src/test/kotlin/dev/usbharu/hideout/activitypub/domain/model/PersonSerializeTest.kt index 9b344337..15c7e506 100644 --- a/src/test/kotlin/dev/usbharu/hideout/activitypub/domain/model/PersonSerializeTest.kt +++ b/src/test/kotlin/dev/usbharu/hideout/activitypub/domain/model/PersonSerializeTest.kt @@ -72,4 +72,68 @@ class PersonSerializeTest { val readValue = objectMapper.readValue(personString) } + + @Test + fun MisskeyのnameがnullのPersonのデシリアライズができる() { + //language=JSON + val json = """{ + "@context": [ + "https://www.w3.org/ns/activitystreams", + "https://w3id.org/security/v1", + { + "manuallyApprovesFollowers": "as:manuallyApprovesFollowers", + "sensitive": "as:sensitive", + "Hashtag": "as:Hashtag", + "quoteUrl": "as:quoteUrl", + "toot": "http://joinmastodon.org/ns#", + "Emoji": "toot:Emoji", + "featured": "toot:featured", + "discoverable": "toot:discoverable", + "schema": "http://schema.org#", + "PropertyValue": "schema:PropertyValue", + "value": "schema:value", + "misskey": "https://misskey-hub.net/ns#", + "_misskey_content": "misskey:_misskey_content", + "_misskey_quote": "misskey:_misskey_quote", + "_misskey_reaction": "misskey:_misskey_reaction", + "_misskey_votes": "misskey:_misskey_votes", + "_misskey_summary": "misskey:_misskey_summary", + "isCat": "misskey:isCat", + "vcard": "http://www.w3.org/2006/vcard/ns#" + } + ], + "type": "Person", + "id": "https://misskey.usbharu.dev/users/9ghwhv9zgg", + "inbox": "https://misskey.usbharu.dev/users/9ghwhv9zgg/inbox", + "outbox": "https://misskey.usbharu.dev/users/9ghwhv9zgg/outbox", + "followers": "https://misskey.usbharu.dev/users/9ghwhv9zgg/followers", + "following": "https://misskey.usbharu.dev/users/9ghwhv9zgg/following", + "featured": "https://misskey.usbharu.dev/users/9ghwhv9zgg/collections/featured", + "sharedInbox": "https://misskey.usbharu.dev/inbox", + "endpoints": { + "sharedInbox": "https://misskey.usbharu.dev/inbox" + }, + "url": "https://misskey.usbharu.dev/@relay_test", + "preferredUsername": "relay_test", + "name": null, + "summary": null, + "_misskey_summary": null, + "icon": null, + "image": null, + "tag": [], + "manuallyApprovesFollowers": true, + "discoverable": true, + "publicKey": { + "id": "https://misskey.usbharu.dev/users/9ghwhv9zgg#main-key", + "type": "Key", + "owner": "https://misskey.usbharu.dev/users/9ghwhv9zgg", + "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA2n5yekTaI4ex5VDWzQfE\nJpWMURAMWl8RcXHLPyLQVQ/PrHp7qatGXmKJUnAOBcq1cwk+VCqTEqx8vJCOZsr1\nMq+D3FMcFdwgtJ0nivPJPx2457b5kfQ4LTkWajcFhj2qixa/XFq6hHei3LDaE6hJ\nGQbdj9NTVlMd7VpiFQkoU09vAPUwGxRoP9Qbc/sh7jrKYFB3iRmY/+zOc+PFpnfn\nG8V1d2v+lnkb9f7t0Z8y2ckk6TVcLPRZktF15eGClVptlgts3hwhrcyrpBs2Dn0U\n35KgIhkhZGAjzk0uyplpfKcserXuGvsjJvelZ3BtMGsuR4kGLHrmiRQp23mIoA1I\n8tfVuV0zPOyO3ruLk2fOjoeZ4XvFHGRNKo66Qx055/8G8Ug5vU8lvIGXm9sflaA9\ntR3AKDNsyxEfjAfrfgJ7cwlKSlLZmkU51jtYEqJ48ZkiIa6fMC0m4QGXdaXmhFWC\no1sGoIErRFpRHewdGlLC9S8R/cMxjex+n8maF0yh79y7aVvU+TS6pRWg5wYjY8r3\nZqAVg/PGRVGAbjVdIdcsjH5ClwAFBW16S633D3m7HJypwwVCzVOvMZqPqcQ/2o8c\nUk+xa88xQG+OPqoAaQqyV9iqsmCMgYM/AcX/BC2h7L2mE/PWoXnoCxGPxr5uvyBf\nHQakDGg4pFZcpVNrDlYo260CAwEAAQ==\n-----END PUBLIC KEY-----\n" + }, + "isCat": false +}""" + + val objectMapper = ActivityPubConfig().objectMapper() + + objectMapper.readValue(json) + } }