Merge pull request #622 from usbharu/domain-test

ドメイン層のテストを追加
This commit is contained in:
usbharu 2024-09-21 17:32:56 +09:00 committed by GitHub
commit 8b5e3b3cec
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
18 changed files with 740 additions and 68 deletions

View File

@ -24,6 +24,7 @@ import dev.usbharu.hideout.core.domain.model.actor.ActorRepository
import dev.usbharu.hideout.core.domain.model.relationship.Relationship import dev.usbharu.hideout.core.domain.model.relationship.Relationship
import dev.usbharu.hideout.core.domain.model.relationship.RelationshipRepository import dev.usbharu.hideout.core.domain.model.relationship.RelationshipRepository
import dev.usbharu.hideout.core.domain.model.support.principal.LocalUser import dev.usbharu.hideout.core.domain.model.support.principal.LocalUser
import dev.usbharu.hideout.core.domain.service.relationship.RelationshipDomainService
import org.slf4j.LoggerFactory import org.slf4j.LoggerFactory
import org.springframework.stereotype.Service import org.springframework.stereotype.Service
@ -32,6 +33,7 @@ class UserFollowRequestApplicationService(
private val relationshipRepository: RelationshipRepository, private val relationshipRepository: RelationshipRepository,
transaction: Transaction, transaction: Transaction,
private val actorRepository: ActorRepository, private val actorRepository: ActorRepository,
private val relationshipDomainService: RelationshipDomainService
) : LocalUserAbstractApplicationService<FollowRequest, Unit>( ) : LocalUserAbstractApplicationService<FollowRequest, Unit>(
transaction, transaction,
logger logger
@ -43,11 +45,15 @@ class UserFollowRequestApplicationService(
val targetId = ActorId(command.targetActorId) val targetId = ActorId(command.targetActorId)
val relationship = relationshipRepository.findByActorIdAndTargetId(actor.id, targetId) ?: Relationship.default( val relationship = relationshipRepository.findByActorIdAndTargetId(actor.id, targetId) ?: Relationship.default(
actor.id, actor.id, targetId
targetId
) )
relationship.followRequest() val inverseRelationship =
relationshipRepository.findByActorIdAndTargetId(targetId, actor.id) ?: Relationship.default(
targetId, actor.id
)
relationshipDomainService.followRequest(relationship, inverseRelationship)
relationshipRepository.save(relationship) relationshipRepository.save(relationship)
} }

View File

@ -82,6 +82,16 @@ class Filter(
} }
override fun hashCode(): Int = id.hashCode() override fun hashCode(): Int = id.hashCode()
override fun toString(): String {
return "Filter(" +
"id=$id, " +
"userDetailId=$userDetailId, " +
"name=$name, " +
"filterContext=$filterContext, " +
"filterAction=$filterAction, " +
"filterKeywords=$filterKeywords" +
")"
}
companion object { companion object {
fun isAllow(user: UserDetail, action: Action, resource: Filter): Boolean { fun isAllow(user: UserDetail, action: Action, resource: Filter): Boolean {

View File

@ -30,7 +30,13 @@ class FilterKeyword(
return id == other.id return id == other.id
} }
override fun hashCode(): Int { override fun hashCode(): Int = id.hashCode()
return id.hashCode()
override fun toString(): String {
return "FilterKeyword(" +
"id=$id, " +
"keyword=$keyword, " +
"mode=$mode" +
")"
} }
} }

View File

@ -29,8 +29,12 @@ class FilterName(name: String) {
return name == other.name return name == other.name
} }
override fun hashCode(): Int { override fun hashCode(): Int = name.hashCode()
return name.hashCode()
override fun toString(): String {
return "FilterName(" +
"name='$name'" +
")"
} }
companion object { companion object {

View File

@ -16,4 +16,29 @@
package dev.usbharu.hideout.core.domain.model.filter package dev.usbharu.hideout.core.domain.model.filter
class FilterResult(val filter: Filter, val matchedKeyword: String) class FilterResult(val filter: Filter, val matchedKeyword: String) {
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (javaClass != other?.javaClass) return false
other as FilterResult
if (filter != other.filter) return false
if (matchedKeyword != other.matchedKeyword) return false
return true
}
override fun hashCode(): Int {
var result = filter.hashCode()
result = 31 * result + matchedKeyword.hashCode()
return result
}
override fun toString(): String {
return "FilterResult(" +
"filter=$filter, " +
"matchedKeyword='$matchedKeyword'" +
")"
}
}

View File

@ -18,4 +18,29 @@ package dev.usbharu.hideout.core.domain.model.filter
import dev.usbharu.hideout.core.domain.model.post.Post import dev.usbharu.hideout.core.domain.model.post.Post
class FilteredPost(val post: Post, val filterResults: List<FilterResult>) class FilteredPost(val post: Post, val filterResults: List<FilterResult>) {
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (javaClass != other?.javaClass) return false
other as FilteredPost
if (post != other.post) return false
if (filterResults != other.filterResults) return false
return true
}
override fun hashCode(): Int {
var result = post.hashCode()
result = 31 * result + filterResults.hashCode()
return result
}
override fun toString(): String {
return "FilteredPost(" +
"post=$post, " +
"filterResults=$filterResults" +
")"
}
}

View File

@ -1,22 +0,0 @@
/*
* Copyright (C) 2024 usbharu
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dev.usbharu.hideout.core.domain.model.followtimeline
import dev.usbharu.hideout.core.domain.model.timeline.TimelineId
import dev.usbharu.hideout.core.domain.model.userdetails.UserDetailId
class FollowTimeline(val userDetailId: UserDetailId, val timelineId: TimelineId)

View File

@ -1,22 +0,0 @@
/*
* Copyright (C) 2024 usbharu
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dev.usbharu.hideout.core.domain.model.followtimeline
interface FollowTimelineRepository {
suspend fun save(followTimeline: FollowTimeline): FollowTimeline
suspend fun delete(followTimeline: FollowTimeline)
}

View File

@ -52,8 +52,8 @@ class Relationship(
addDomainEvent(relationshipEventFactory.createEvent(RelationshipEvent.UNFOLLOW_REQUEST)) addDomainEvent(relationshipEventFactory.createEvent(RelationshipEvent.UNFOLLOW_REQUEST))
} }
fun block() { private fun block() {
require(following.not()) unfollow()
blocking = true blocking = true
addDomainEvent(RelationshipEventFactory(this).createEvent(RelationshipEvent.BLOCK)) addDomainEvent(RelationshipEventFactory(this).createEvent(RelationshipEvent.BLOCK))
} }
@ -81,7 +81,7 @@ class Relationship(
mutingFollowRequest = false mutingFollowRequest = false
} }
fun followRequest() { private fun followRequest() {
require(blocking.not()) require(blocking.not())
followRequesting = true followRequesting = true
addDomainEvent(RelationshipEventFactory(this).createEvent(RelationshipEvent.FOLLOW_REQUEST)) addDomainEvent(RelationshipEventFactory(this).createEvent(RelationshipEvent.FOLLOW_REQUEST))
@ -123,6 +123,17 @@ class Relationship(
return result return result
} }
@Suppress("UnnecessaryAbstractClass")
abstract class InternalRelationshipDomainService {
protected fun block(relationship: Relationship) {
relationship.block()
}
protected fun followRequest(relationship: Relationship) {
relationship.followRequest()
}
}
companion object { companion object {
fun default(actorId: ActorId, targetActorId: ActorId): Relationship = Relationship( fun default(actorId: ActorId, targetActorId: ActorId): Relationship = Relationship(
actorId = actorId, actorId = actorId,

View File

@ -77,12 +77,12 @@ class DefaultPostReadAccessControl(private val relationshipRepository: Relations
override suspend fun areAllows(postList: List<Post>, principal: Principal): List<Post> { override suspend fun areAllows(postList: List<Post>, principal: Principal): List<Post> {
val actorIds = postList.map { it.actorId } val actorIds = postList.map { it.actorId }
val relationshipList = val blockedByList =
relationshipRepository.findByActorIdsAndTargetIdAndBlocking(actorIds, principal.actorId, true) relationshipRepository.findByActorIdsAndTargetIdAndBlocking(actorIds, principal.actorId, true)
.map { it.actorId } .map { it.actorId }
val inverseRelationshipList = val followingList =
relationshipRepository.findByActorIdAndTargetIdsAndFollowing(principal.actorId, actorIds, true) relationshipRepository.findByActorIdAndTargetIdsAndFollowing(principal.actorId, actorIds, true)
.map { it.actorId } .map { it.targetActorId }
fun internalAllow(post: Post): Boolean { fun internalAllow(post: Post): Boolean {
// ポスト主は無条件で見れる // ポスト主は無条件で見れる
@ -90,7 +90,7 @@ class DefaultPostReadAccessControl(private val relationshipRepository: Relations
return true return true
} }
if (relationshipList.contains(post.actorId)) { if (blockedByList.contains(post.actorId)) {
return false return false
} }
@ -106,7 +106,7 @@ class DefaultPostReadAccessControl(private val relationshipRepository: Relations
return true return true
} }
if (post.visibility == Visibility.FOLLOWERS && inverseRelationshipList.contains(principal.actorId)) { if (post.visibility == Visibility.FOLLOWERS && followingList.contains(post.actorId)) {
return true return true
} }
return false return false

View File

@ -17,17 +17,28 @@
package dev.usbharu.hideout.core.domain.service.relationship package dev.usbharu.hideout.core.domain.service.relationship
import dev.usbharu.hideout.core.domain.model.relationship.Relationship import dev.usbharu.hideout.core.domain.model.relationship.Relationship
import dev.usbharu.hideout.core.domain.model.relationship.Relationship.InternalRelationshipDomainService
import org.springframework.stereotype.Service import org.springframework.stereotype.Service
@Service @Service
class RelationshipDomainService { class RelationshipDomainService : InternalRelationshipDomainService() {
fun block(relationship: Relationship, inverseRelationship: Relationship) { fun block(relationship: Relationship, inverseRelationship: Relationship) {
require(relationship != inverseRelationship) require(relationship != inverseRelationship)
require(relationship.actorId == inverseRelationship.targetActorId) require(relationship.actorId == inverseRelationship.targetActorId)
require(relationship.targetActorId == inverseRelationship.actorId) require(relationship.targetActorId == inverseRelationship.actorId)
relationship.block() block(relationship)
inverseRelationship.unfollow() inverseRelationship.unfollow()
inverseRelationship.unfollowRequest() inverseRelationship.unfollowRequest()
} }
fun followRequest(relationship: Relationship, inverseRelationship: Relationship) {
require(relationship != inverseRelationship)
require(relationship.actorId == inverseRelationship.targetActorId)
require(relationship.targetActorId == inverseRelationship.actorId)
require(inverseRelationship.blocking.not())
require(relationship.blocking.not())
followRequest(relationship)
}
} }

View File

@ -27,7 +27,7 @@ import org.springframework.beans.factory.annotation.Value
import org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator import org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator
import java.sql.SQLException import java.sql.SQLException
@Suppress("VarCouldBeVal") @Suppress("VarCouldBeVal", "UnnecessaryAbstractClass")
abstract class AbstractRepository(protected val logger: Logger) { abstract class AbstractRepository(protected val logger: Logger) {
private val sqlErrorCodeSQLExceptionTranslator = SQLErrorCodeSQLExceptionTranslator() private val sqlErrorCodeSQLExceptionTranslator = SQLErrorCodeSQLExceptionTranslator()
private val springDataAccessExceptionSQLExceptionTranslator = SpringDataAccessExceptionSQLExceptionTranslator() private val springDataAccessExceptionSQLExceptionTranslator = SpringDataAccessExceptionSQLExceptionTranslator()

View File

@ -0,0 +1,152 @@
package dev.usbharu.hideout.core.domain.model.relationship
import dev.usbharu.hideout.core.domain.event.relationship.RelationshipEvent
import dev.usbharu.hideout.core.domain.model.actor.ActorId
import org.junit.jupiter.api.Test
import utils.AssertDomainEvent.assertContainsEvent
import kotlin.test.assertFalse
import kotlin.test.assertTrue
class RelationshipTest {
@Test
fun unfollow_フォローとフォローリクエストが取り消されUNFOLLOWとUNFOLLOW_REQUESTが発生する() {
val relationship = Relationship(
actorId = ActorId(1),
targetActorId = ActorId(2),
following = true,
blocking = false,
muting = false,
followRequesting = false,
mutingFollowRequest = false
)
relationship.unfollow()
assertFalse(relationship.following)
assertFalse(relationship.followRequesting)
assertContainsEvent(relationship, RelationshipEvent.UNFOLLOW.eventName)
assertContainsEvent(relationship, RelationshipEvent.UNFOLLOW_REQUEST.eventName)
}
@Test
fun mute_MUTEが発生する() {
val relationship = Relationship(
actorId = ActorId(1),
targetActorId = ActorId(2),
following = true,
blocking = false,
muting = false,
followRequesting = false,
mutingFollowRequest = false
)
relationship.mute()
assertTrue(relationship.muting)
assertContainsEvent(relationship, RelationshipEvent.MUTE.eventName)
}
@Test
fun unmute_UNMUTEが発生する() {
val relationship = Relationship(
actorId = ActorId(1),
targetActorId = ActorId(2),
following = true,
blocking = false,
muting = true,
followRequesting = false,
mutingFollowRequest = true
)
relationship.unmute()
assertFalse(relationship.muting)
assertContainsEvent(relationship, RelationshipEvent.UNMUTE.eventName)
}
@Test
fun muteFollowRequest_muteFollowiRequestがtrueになる() {
val relationship = Relationship(
actorId = ActorId(1),
targetActorId = ActorId(2),
following = true,
blocking = false,
muting = false,
followRequesting = true,
mutingFollowRequest = false
)
relationship.muteFollowRequest()
assertTrue(relationship.mutingFollowRequest)
}
@Test
fun unmuteFollowRequest_muteFollowiRequestがfalseになる() {
val relationship = Relationship(
actorId = ActorId(1),
targetActorId = ActorId(2),
following = true,
blocking = false,
muting = false,
followRequesting = true,
mutingFollowRequest = true
)
relationship.unmuteFollowRequest()
assertFalse(relationship.mutingFollowRequest)
}
@Test
fun unfollowRequest_followRequestingがfalseになりUNFOLLOW_REQUESTが発生する() {
val relationship = Relationship(
ActorId(1),
targetActorId = ActorId(2),
following = false,
blocking = false,
muting = false,
followRequesting = true,
mutingFollowRequest = false
)
relationship.unfollowRequest()
assertFalse(relationship.followRequesting)
assertContainsEvent(relationship, RelationshipEvent.UNFOLLOW_REQUEST.eventName)
}
@Test
fun acceptFollowRequest_followingがtrueにfollowRequestingがfalseになりaccept_followが発生する() {
val relationship = Relationship(
actorId = ActorId(1),
targetActorId = ActorId(2),
following = false,
blocking = false,
muting = false,
followRequesting = true,
mutingFollowRequest = true
)
relationship.acceptFollowRequest()
assertTrue(relationship.following)
assertContainsEvent(relationship, RelationshipEvent.ACCEPT_FOLLOW.eventName)
}
@Test
fun rejectFollowRequest_followRequestingがfalseになりREJECT_FOLLOWが発生する() {
val relationship = Relationship(
actorId = ActorId(1),
targetActorId = ActorId(2),
following = false,
blocking = false,
muting = false,
followRequesting = true,
mutingFollowRequest = false
)
relationship.rejectFollowRequest()
assertFalse(relationship.followRequesting)
assertContainsEvent(relationship, RelationshipEvent.REJECT_FOLLOW.eventName)
}
}

View File

@ -0,0 +1,86 @@
package dev.usbharu.hideout.core.domain.service.filter
import dev.usbharu.hideout.core.domain.model.filter.*
import dev.usbharu.hideout.core.domain.model.post.TestPostFactory
import dev.usbharu.hideout.core.domain.model.userdetails.UserDetailId
import org.junit.jupiter.api.Test
import kotlin.test.assertEquals
class FilterDomainServiceTest {
@Test
fun apply_filterContextの適用範囲にフィルターが適用される() {
val post = TestPostFactory.create()
val domainService = FilterDomainService()
val filter = Filter(
FilterId(1),
userDetailId = UserDetailId(1),
FilterName("filter"),
setOf(FilterContext.HOME),
filterAction = FilterAction.HIDE,
setOf(FilterKeyword(FilterKeywordId(1), FilterKeywordKeyword("test"), FilterMode.NONE))
)
val apply = domainService.apply(post, FilterContext.HOME, listOf(filter))
assertEquals(1, apply.filterResults.size)
assertEquals("test", apply.filterResults.first().matchedKeyword)
}
@Test
fun apply_filterContextに当てはまらないならfilterResultsが空になる() {
val post = TestPostFactory.create()
val domainService = FilterDomainService()
val filter = Filter(
FilterId(1),
userDetailId = UserDetailId(1),
FilterName("filter"),
setOf(FilterContext.PUBLIC),
filterAction = FilterAction.HIDE,
setOf(FilterKeyword(FilterKeywordId(1), FilterKeywordKeyword("test"), FilterMode.NONE))
)
val apply = domainService.apply(post, FilterContext.HOME, listOf(filter))
assertEquals(0, apply.filterResults.size)
}
@Test
fun overviewにも適用される() {
val post = TestPostFactory.create(overview = "test")
val domainService = FilterDomainService()
val filter = Filter(
FilterId(1),
userDetailId = UserDetailId(1),
FilterName("filter"),
setOf(FilterContext.HOME),
filterAction = FilterAction.HIDE,
setOf(FilterKeyword(FilterKeywordId(1), FilterKeywordKeyword("test"), FilterMode.NONE))
)
val apply = domainService.apply(post, FilterContext.HOME, listOf(filter))
assertEquals(2, apply.filterResults.size)
assertEquals("test", apply.filterResults.first().matchedKeyword)
}
@Test
fun applyAll_filterContextの適用範囲にフィルターが適用される() {
val postList = listOf(
TestPostFactory.create(),
TestPostFactory.create(),
TestPostFactory.create(content = "aaaaaaaaaa"),
TestPostFactory.create(),
TestPostFactory.create()
)
val filter = Filter(
FilterId(1),
userDetailId = UserDetailId(1),
FilterName("filter"),
setOf(FilterContext.HOME),
filterAction = FilterAction.HIDE,
setOf(FilterKeyword(FilterKeywordId(1), FilterKeywordKeyword("test"), FilterMode.NONE))
)
val filteredPosts = FilterDomainService().applyAll(postList, FilterContext.HOME, filters = listOf(filter))
assertEquals(5, filteredPosts.size)
}
}

View File

@ -1,6 +1,7 @@
package dev.usbharu.hideout.core.domain.service.post package dev.usbharu.hideout.core.domain.service.post
import dev.usbharu.hideout.core.domain.model.actor.ActorId import dev.usbharu.hideout.core.domain.model.actor.ActorId
import dev.usbharu.hideout.core.domain.model.post.Post
import dev.usbharu.hideout.core.domain.model.post.TestPostFactory import dev.usbharu.hideout.core.domain.model.post.TestPostFactory
import dev.usbharu.hideout.core.domain.model.post.Visibility import dev.usbharu.hideout.core.domain.model.post.Visibility
import dev.usbharu.hideout.core.domain.model.relationship.Relationship import dev.usbharu.hideout.core.domain.model.relationship.Relationship
@ -13,12 +14,14 @@ import kotlinx.coroutines.test.runTest
import org.junit.jupiter.api.Assertions.assertFalse import org.junit.jupiter.api.Assertions.assertFalse
import org.junit.jupiter.api.Assertions.assertTrue import org.junit.jupiter.api.Assertions.assertTrue
import org.junit.jupiter.api.Test import org.junit.jupiter.api.Test
import org.junit.jupiter.api.assertAll
import org.junit.jupiter.api.extension.ExtendWith import org.junit.jupiter.api.extension.ExtendWith
import org.mockito.InjectMocks import org.mockito.InjectMocks
import org.mockito.Mock import org.mockito.Mock
import org.mockito.junit.jupiter.MockitoExtension import org.mockito.junit.jupiter.MockitoExtension
import org.mockito.kotlin.doReturn import org.mockito.kotlin.*
import org.mockito.kotlin.whenever import kotlin.test.assertContentEquals
import kotlin.test.assertEquals
@ExtendWith(MockitoExtension::class) @ExtendWith(MockitoExtension::class)
class DefaultPostReadAccessControlTest { class DefaultPostReadAccessControlTest {
@ -155,4 +158,217 @@ class DefaultPostReadAccessControlTest {
assertFalse(actual) assertFalse(actual)
} }
@Test
fun ポスト主は無条件で見れる() = runTest {
val actual = service.isAllow(
TestPostFactory.create(actorId = 1, visibility = Visibility.DIRECT),
LocalUser(ActorId(1), UserDetailId(1), Acct("test", "example.com"))
)
assertTrue(actual)
}
@Test
fun areAllows_ポスト主は無条件で見れる() = runTest {
whenever(
relationshipRepository.findByActorIdsAndTargetIdAndBlocking(
any(),
anyValueClass(),
eq(true)
)
).doReturn(
emptyList()
)
whenever(
relationshipRepository.findByActorIdAndTargetIdsAndFollowing(
anyValueClass(),
any(),
eq(true)
)
).doReturn(
emptyList()
)
val postList = listOf<Post>(
TestPostFactory.create(actorId = 1, visibility = Visibility.DIRECT),
TestPostFactory.create(actorId = 1, visibility = Visibility.FOLLOWERS),
TestPostFactory.create(actorId = 1, visibility = Visibility.UNLISTED),
TestPostFactory.create(actorId = 1, visibility = Visibility.PUBLIC),
)
val actual = service.areAllows(postList, LocalUser(ActorId(1), UserDetailId(1), Acct("test", "example.com")))
assertContentEquals(postList, actual)
}
@Test
fun areFollows_ブロックされていたら見れない() = runTest {
whenever(
relationshipRepository.findByActorIdsAndTargetIdAndBlocking(
any(),
anyValueClass(),
eq(true)
)
).doReturn(
listOf(Relationship.default(actorId = ActorId(2), targetActorId = ActorId(1)))
)
whenever(
relationshipRepository.findByActorIdAndTargetIdsAndFollowing(
anyValueClass(),
any(),
eq(true)
)
).doReturn(
emptyList()
)
val postList = listOf<Post>(
TestPostFactory.create(actorId = 1, visibility = Visibility.DIRECT),
TestPostFactory.create(actorId = 2, visibility = Visibility.FOLLOWERS),
TestPostFactory.create(actorId = 1, visibility = Visibility.UNLISTED),
TestPostFactory.create(actorId = 1, visibility = Visibility.PUBLIC),
)
val actual = service.areAllows(postList, LocalUser(ActorId(1), UserDetailId(1), Acct("test", "example.com")))
assertEquals(3, actual.size)
assertAll(actual.map { { assertEquals(1, it.actorId.id) } })
}
@Test
fun areAllows_PUBLICとUNLISTEDは見れる() = runTest {
whenever(
relationshipRepository.findByActorIdsAndTargetIdAndBlocking(
any(),
anyValueClass(),
eq(true)
)
).doReturn(
emptyList()
)
whenever(
relationshipRepository.findByActorIdAndTargetIdsAndFollowing(
anyValueClass(),
any(),
eq(true)
)
).doReturn(
emptyList()
)
val postList = listOf<Post>(
TestPostFactory.create(actorId = 3, visibility = Visibility.DIRECT),
TestPostFactory.create(actorId = 3, visibility = Visibility.FOLLOWERS),
TestPostFactory.create(actorId = 3, visibility = Visibility.UNLISTED),
TestPostFactory.create(actorId = 3, visibility = Visibility.PUBLIC),
)
val actual = service.areAllows(postList, LocalUser(ActorId(1), UserDetailId(1), Acct("test", "example.com")))
assertEquals(2, actual.size)
kotlin.test.assertTrue(actual.all { it.visibility == Visibility.PUBLIC || it.visibility == Visibility.UNLISTED })
}
@Test
fun areAllows_Anonymousは見れない() = runTest {
whenever(
relationshipRepository.findByActorIdsAndTargetIdAndBlocking(
any(),
anyValueClass(),
eq(true)
)
).doReturn(
emptyList()
)
whenever(
relationshipRepository.findByActorIdAndTargetIdsAndFollowing(
anyValueClass(),
any(),
eq(true)
)
).doReturn(
emptyList()
)
val postList = listOf<Post>(
TestPostFactory.create(actorId = 3, visibility = Visibility.DIRECT),
TestPostFactory.create(actorId = 3, visibility = Visibility.FOLLOWERS),
TestPostFactory.create(actorId = 3, visibility = Visibility.UNLISTED),
TestPostFactory.create(actorId = 3, visibility = Visibility.PUBLIC),
)
val actual = service.areAllows(postList, Anonymous)
assertEquals(2, actual.size)
kotlin.test.assertTrue(actual.all { it.visibility == Visibility.PUBLIC || it.visibility == Visibility.UNLISTED })
}
@Test
fun areAllows_DIRECTはVisibleActorsに入っていたら見れる() = runTest {
whenever(
relationshipRepository.findByActorIdsAndTargetIdAndBlocking(
any(),
anyValueClass(),
eq(true)
)
).doReturn(
emptyList()
)
whenever(
relationshipRepository.findByActorIdAndTargetIdsAndFollowing(
anyValueClass(),
any(),
eq(true)
)
).doReturn(
emptyList()
)
val postList = listOf<Post>(
TestPostFactory.create(id = 1, actorId = 3, visibility = Visibility.DIRECT, visibleActors = listOf(1)),
TestPostFactory.create(id = 2, actorId = 3, visibility = Visibility.DIRECT, visibleActors = listOf(2)),
TestPostFactory.create(id = 3, actorId = 3, visibility = Visibility.DIRECT, visibleActors = listOf(3)),
TestPostFactory.create(
id = 4,
actorId = 3,
visibility = Visibility.DIRECT,
visibleActors = listOf(1, 2, 3, 4)
),
)
val actual = service.areAllows(postList, LocalUser(ActorId(1), UserDetailId(1), Acct("test", "example.com")))
assertEquals(2, actual.size)
kotlin.test.assertTrue(actual.all { it.id.id == 1L || it.id.id == 4L })
}
@Test
fun areAllows_FOLLOWERSはフォローされていたら見れる() = runTest {
whenever(
relationshipRepository.findByActorIdsAndTargetIdAndBlocking(
any(),
anyValueClass(),
eq(true)
)
).doReturn(
emptyList()
)
whenever(
relationshipRepository.findByActorIdAndTargetIdsAndFollowing(
anyValueClass(),
any(),
eq(true)
)
).doReturn(
listOf(Relationship.default(actorId = ActorId(1), targetActorId = ActorId(2)))
)
val postList = listOf<Post>(
TestPostFactory.create(actorId = 3, visibility = Visibility.FOLLOWERS),
TestPostFactory.create(actorId = 2, visibility = Visibility.FOLLOWERS),
TestPostFactory.create(actorId = 3, visibility = Visibility.FOLLOWERS),
TestPostFactory.create(actorId = 3, visibility = Visibility.FOLLOWERS),
)
val actual = service.areAllows(postList, LocalUser(ActorId(1), UserDetailId(1), Acct("test", "example.com")))
assertEquals(1, actual.size)
assertAll(actual.map { { assertEquals(2, it.actorId.id) } })
}
} }

View File

@ -0,0 +1,136 @@
package dev.usbharu.hideout.core.domain.service.relationship
import dev.usbharu.hideout.core.domain.model.actor.ActorId
import dev.usbharu.hideout.core.domain.model.relationship.Relationship
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.assertThrows
import kotlin.test.assertFalse
import kotlin.test.assertTrue
class RelationshipDomainServiceTest {
@Test
fun block_relationshipとinverseRelationshipが同じ場合失敗() {
val relationship = Relationship.default(ActorId(1), ActorId(2))
assertThrows<IllegalArgumentException> {
RelationshipDomainService().block(relationship, relationship)
}
}
@Test
fun block_relationship_actorIdとinverseRelationshio_targetActorIdが同じ場合失敗() {
val relationship = Relationship.default(ActorId(1), ActorId(2))
val inverseRelationship = Relationship.default(ActorId(2), ActorId(2))
assertThrows<IllegalArgumentException> {
RelationshipDomainService().block(relationship, inverseRelationship)
}
}
@Test
fun block_relationship_targetActorIdとinverseRelationship_actorIdが同じ場合失敗() {
val relationship = Relationship.default(ActorId(1), ActorId(2))
val inverseRelationship = Relationship.default(ActorId(1), ActorId(1))
assertThrows<IllegalArgumentException> {
RelationshipDomainService().block(relationship, inverseRelationship)
}
}
@Test
fun block_ブロックされお互いのフォローとフォローリクエストが外れる() {
val relationship = Relationship(
ActorId(1),
ActorId(2),
following = true,
blocking = false,
muting = false,
followRequesting = false,
mutingFollowRequest = false
)
val inverseRelationship = Relationship(
ActorId(2),
ActorId(1),
following = false,
blocking = false,
followRequesting = true,
mutingFollowRequest = false,
muting = false
)
RelationshipDomainService().block(relationship, inverseRelationship)
assertTrue(relationship.blocking)
assertFalse(relationship.following)
assertFalse(relationship.followRequesting)
assertFalse(inverseRelationship.following)
assertFalse(inverseRelationship.followRequesting)
}
@Test
fun followRequest_relationshipとinverseRelationshipが同じ場合失敗() {
val relationship = Relationship.default(ActorId(1), ActorId(2))
assertThrows<IllegalArgumentException> {
RelationshipDomainService().followRequest(relationship, relationship)
}
}
@Test
fun followRequest_relationship_actorIdとinverseRelationshio_targetActorIdが同じ場合失敗() {
val relationship = Relationship.default(ActorId(1), ActorId(2))
val inverseRelationship = Relationship.default(ActorId(2), ActorId(2))
assertThrows<IllegalArgumentException> {
RelationshipDomainService().followRequest(relationship, inverseRelationship)
}
}
@Test
fun followRequest_relationship_targetActorIdとinverseRelationship_actorIdが同じ場合失敗() {
val relationship = Relationship.default(ActorId(1), ActorId(2))
val inverseRelationship = Relationship.default(ActorId(1), ActorId(1))
assertThrows<IllegalArgumentException> {
RelationshipDomainService().followRequest(relationship, inverseRelationship)
}
}
@Test
fun followRequest_ブロックされてる場合失敗() {
val relationship = Relationship.default(ActorId(1), ActorId(2))
val inverseRelationship = Relationship(
ActorId(2),
ActorId(1),
following = false,
blocking = true,
muting = false,
followRequesting = false,
mutingFollowRequest = false
)
assertThrows<IllegalArgumentException> {
RelationshipDomainService().followRequest(relationship, inverseRelationship)
}
}
@Test
fun followRequest_ブロックしてる場合は失敗() {
val relationship = Relationship(
ActorId(1),
ActorId(2),
following = false,
blocking = true,
muting = false,
followRequesting = false,
mutingFollowRequest = false
)
val inverseRelationship = Relationship.default(ActorId(2), ActorId(1))
assertThrows<IllegalArgumentException> {
RelationshipDomainService().followRequest(relationship, inverseRelationship)
}
}
@Test
fun followRequest_followRequestingがtrueになる() {
val relationship = Relationship.default(ActorId(1), ActorId(2))
val inverseRelationship = Relationship.default(ActorId(2), ActorId(1))
RelationshipDomainService().followRequest(relationship, inverseRelationship)
assertTrue(relationship.followRequesting)
}
}

View File

@ -0,0 +1,28 @@
package dev.usbharu.hideout.core.domain.service.userdetail
import dev.usbharu.hideout.core.infrastructure.springframework.SpringSecurityPasswordEncoder
import kotlinx.coroutines.test.runTest
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.extension.ExtendWith
import org.mockito.InjectMocks
import org.mockito.Spy
import org.mockito.junit.jupiter.MockitoExtension
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder
import kotlin.test.assertNotEquals
@ExtendWith(MockitoExtension::class)
class UserDetailDomainServiceTest {
@InjectMocks
lateinit var userDetailDomainService: UserDetailDomainService
@Spy
val passwordEncoder: PasswordEncoder = SpringSecurityPasswordEncoder(BCryptPasswordEncoder())
@Test
fun hash() = runTest {
val hashedPassword = userDetailDomainService.hashPassword("password")
assertNotEquals("password", hashedPassword.password)
}
}

View File

@ -464,7 +464,7 @@ class ExposedRelationshipRepositoryTest : AbstractRepositoryTest(Relationships)
mutingFollowRequest = false, mutingFollowRequest = false,
) )
relationship.block() relationship.mute()
repository.save(relationship) repository.save(relationship)
@ -492,7 +492,7 @@ class ExposedRelationshipRepositoryTest : AbstractRepositoryTest(Relationships)
followRequesting = false, followRequesting = false,
mutingFollowRequest = false, mutingFollowRequest = false,
) )
relationship.block() relationship.mute()
repository.delete(relationship) repository.delete(relationship)